MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Progetto per filtrare la proprietà all'interno del secondo array nidificato

Poiché il tuo requisito è semplicemente "proiettare" il documento in modo che il campo sia mascherato, sì, il framework di aggregazione è uno strumento per farlo. Ci vuole un po' per capire il processo durante lo svolgimento degli array e la ricostruzione.

Quindi quello che volevi era questo:

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

Ma in realtà, se hai una versione MongoDB 2.6 o successiva, non è necessario $unwind e $group i risultati di nuovo insieme per omettere quel campo. Ora puoi semplicemente farlo usando $project e $map operatore che funziona con gli array:

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

Ci scusiamo per il rientro che scorre un po' fuori dalla pagina, ma è comunque più facile da leggere in confronto.

Il primo $map elabora l'array di domande sul posto e invia a un $map che restituisce i documenti dell'array di risposte interne senza il campo "isCorrectAnswer". Utilizza le proprie variabili per rappresentare gli elementi e l'utilizzo di $ifNull in c'è solo perché la parte "in" di $map l'operatore si aspetta di valutare una condizione su ciascuno di questi elementi.

Nel complesso un po' più veloce, poiché non è necessario passare attraverso il $unwind e $group operazioni solo per rimuovere il campo. Quindi diventa davvero solo la "proiezione" che potresti aspettarti.