sql >> Database >  >> NoSQL >> MongoDB

Project om eigenschap binnen tweede geneste array te filteren

Aangezien het uw vereiste is om het document gewoon te "projecteren", zodat het veld wordt gemaskeerd, is het aggregatieraamwerk inderdaad een hulpmiddel om dit te doen. Het kost wat tijd om je hoofd rond het proces te krijgen bij het afwikkelen van arrays en het reconstrueren.

Dus wat je wilde was dit:

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" }
    }}
])

Maar echt, als je een MongoDB 2.6 of hogere versie hebt, hoef je niet $unwind en $group de resultaten weer bij elkaar om dat veld weg te laten. Je kunt dit nu gewoon doen met $project en de $map operator die met arrays werkt:

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
                    ]
                }
            }
        }
    }}
])

Sorry voor de inspringing die daar een beetje van de pagina rolt, maar het is nog steeds gemakkelijker te lezen in vergelijking.

De eerste $map verwerkt de vragenreeks op zijn plaats en feeds naar een innerlijke $map die de innerlijke antwoorden-array-documenten retourneert zonder het veld "isCorrectAnswer". Het gebruikt zijn eigen variabelen om de elementen weer te geven, en het gebruik van $ifNull daar zit alleen maar in omdat het "in" deel van de $map de operator verwacht een voorwaarde voor elk van deze elementen te evalueren.

Over het algemeen een beetje sneller, omdat je niet door de $unwind en $group bewerkingen om het veld te verwijderen. Het wordt dus echt de "projectie" die je zou verwachten.



  1. Mongoose findOne ingesloten document door _id

  2. sorteer mongo-verzameling op basis van de score van onderliggende documenten

  3. Update array-element in mongo

  4. Paginering van subdocumenten in Mongoose