MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Projet pour filtrer la propriété dans le deuxième tableau imbriqué

Étant donné que votre exigence est simplement de "projeter" le document afin que le champ soit masqué, oui, le cadre d'agrégation est un outil pour le faire. Il faut un peu de temps pour comprendre le processus lors du déroulement des tableaux et de la reconstruction.

Donc, ce que vous vouliez, c'était ceci :

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

Mais vraiment, si vous avez une version MongoDB 2.6 ou supérieure, vous n'avez pas besoin de $unwind et $group les résultats de nouveau ensemble afin d'omettre ce champ. Vous pouvez maintenant le faire en utilisant $project et le $map opérateur qui fonctionne avec des tableaux :

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

Désolé pour l'indentation qui défile un peu sur la page, mais c'est toujours plus facile à lire en comparaison.

Le premier $map traite le tableau de questions en place et alimente un $map qui renvoie les documents du tableau de réponses internes sans le champ "isCorrectAnswer". Il utilise ses propres variables pour représenter les éléments et l'utilisation de $ifNull il y a juste parce que la partie "in" du $map l'opérateur s'attend à évaluer une condition sur chacun de ces éléments.

Globalement un peu plus rapide, car vous n'avez pas à passer par le $unwind et $group opérations juste pour supprimer le champ. Cela devient donc vraiment la "projection" à laquelle vous pourriez vous attendre.