sql >> Databasteknik >  >> NoSQL >> MongoDB

Projekt för att filtrera egenskapen inom den andra kapslade arrayen

Eftersom ditt krav är att bara "projicera" dokumentet så att fältet är maskerat, ja aggregeringsramverket är ett verktyg för att göra detta. Det tar dock lite att komma runt processen när du lindar upp arrayer och rekonstruerar.

Så det du ville ha var detta:

db.collection.aggregate([
    { "$unwind": "$questions" },
    { "$unwind": "$questions.answers" },
    { "$group": { 
        "_id": {
            "_id": "$_id",
            "name": "$name",
            "description": "$description",
            "qid": "$questions._id",
            "question": "$questions.question"
        },
        "answers": {
            "$push": {
                "_id": "$questions.answers._id",
                "answer": "$questions.answers.answer"
            }
        }
    }},
    { "$project": {
        "questions": {
            "_id": "$_id.qid",
            "question": "$_id.question",
            "answers": "$answers"
        }
    }},
    { "$sort": { "_id": 1, "questions._id": 1 } },
    { "$group": {
        "_id": "$_id._id",
        "name": { "$first": "$_id.name" },
        "description": { "$first": "$_id.description" },
        "questions": { "$push": "$questions" }
    }}
])

Men egentligen, om du har en MongoDB 2.6 eller senare version behöver du inte $unwind och $group resultaten sammanförs igen för att utelämna det fältet. Du kan nu bara göra detta med $project och $map operator som fungerar med arrayer:

db.collection.aggregate([
    { "$project": {
        "name": 1,
        "description": 1,
        "questions": {
            "$map": {
                "input": "$questions",
                "as": "q",
                "in": {
                    "$ifNull": [
                        { 
                            "_id": "$$q._id",
                            "question": "$$q.question",
                            "answers": {
                                "$map": {
                                    "input": "$$q.answers",
                                    "as": "el",
                                    "in": {
                                        "$ifNull": [
                                            { "_id": "$$el._id", "answer": "$$el.answer" },
                                            false
                                        ]
                                    }
                                }
                            }
                        },
                        false
                    ]
                }
            }
        }
    }}
])

Ursäkta för indraget som rullar av sidan lite där, men det är ändå lättare att läsa i jämförelse.

Den första $map behandlar frågeuppsättningen på plats och matar till en inre $map som returnerar de inre svarsarraydokumenten utan fältet "isCorrectAnswer". Den använder sina egna variabler för att representera elementen, och användningen av $ifNull där är bara för att "in"-delen av $map operatören förväntar sig att utvärdera ett villkor för vart och ett av dessa element.

Sammantaget lite snabbare, eftersom du inte behöver gå igenom $unwind och $group operationer bara för att ta bort fältet. Så det blir egentligen bara den "projektion" som du kan förvänta dig.



  1. Behöver jag avsluta min nod redis-klientinstans med .quit()?

  2. Django med MongoDB

  3. Använder AngularJs och MongoDB/Mongoose

  4. Autentiseringsfel vid anslutning till Mongo Atlas från Mule