MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Projeto para filtrar a propriedade na segunda matriz aninhada


Como seu requisito é apenas "projetar" o documento para que o campo seja mascarado, sim, a estrutura de agregação é uma ferramenta para fazer isso. Demora um pouco para entender o processo ao desenrolar matrizes e reconstruir.

Então o que você queria era isso:
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" }
    }}
])

Mas, na verdade, se você tiver uma versão do MongoDB 2.6 ou superior, não precisará $unwind e $group os resultados novamente para omitir esse campo. Agora você pode fazer isso usando $project e o $map operador que trabalha com arrays:
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
                    ]
                }
            }
        }
    }}
])

Desculpe pelo recuo rolando um pouco para fora da página, mas ainda é mais fácil de ler por comparação.

O primeiro $map processa a matriz de perguntas no local e alimenta um $map que retorna os documentos da matriz de respostas internas sem o campo "isCorrectAnswer". Ele usa suas próprias variáveis ​​para representar os elementos e o uso de $ifNull lá é apenas porque a parte "in" do $map operador espera avaliar uma condição em cada um desses elementos.

No geral, um pouco mais rápido, pois você não precisa passar pelo $unwind e $group operações apenas para remover o campo. Então realmente se torna apenas a "projeção" que você poderia esperar.