MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Projekt zum Filtern der Eigenschaft innerhalb des zweiten verschachtelten Arrays

Da Ihre Anforderung darin besteht, das Dokument nur zu "projizieren", damit das Feld maskiert wird, ist das Aggregationsframework ein Werkzeug dafür. Es dauert jedoch ein bisschen, bis Sie sich mit dem Prozess vertraut gemacht haben, wenn Sie Arrays abwickeln und rekonstruieren.

Sie wollten also Folgendes:

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

Aber wirklich, wenn Sie eine Version von MongoDB 2.6 oder höher haben, müssen Sie nicht $unwind und $group die Ergebnisse wieder zusammen, um dieses Feld auszulassen. Sie können dies jetzt einfach mit $project und der $map Operator, der mit Arrays arbeitet:

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

Entschuldigung für die Einrückung, die dort ein wenig von der Seite wegscrollt, aber es ist im Vergleich immer noch einfacher zu lesen.

Der erste $map verarbeitet das Fragen-Array an Ort und Stelle und speist es in einen inneren $map das die inneren Antworten-Array-Dokumente ohne das Feld „isCorrectAnswer“ zurückgibt. Es verwendet seine eigenen Variablen zur Darstellung der Elemente und die Verwendung von $ifNull drin ist nur, weil der "in"-Teil von $map Operator erwartet, eine Bedingung für jedes dieser Elemente auszuwerten.

Insgesamt etwas schneller, da Sie den $unwind und $group Operationen, nur um das Feld zu entfernen. Es wird also wirklich nur die "Projektion", die Sie vielleicht erwarten.