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

Campos de subdoc de seleção do Mongoose


É assim que o MongoDB lida com a projeção básica com elementos de matriz. Enquanto você pode fazer algo assim:
Model.findOne({}, { "comments.upvotes": 1 },function(err,doc) {

})

E isso apenas retornaria o campo "upvotes" de dentro dos subdocumentos da matriz de comentários para todos os documentos que correspondam à condição e a todos os elementos da matriz, é claro, você não pode combinar isso com uma projeção posicional selecionada usando o $ posicional operador. Isso basicamente decorre da "teoria" que geralmente você realmente deseja retornar o array inteiro. Portanto, é assim que sempre funcionou e não é provável que mude em breve.

Para obter o que deseja, você precisa dos recursos estendidos para manipulação de documentos oferecidos pelo estrutura de agregação . Isso lhe dá mais controle sobre como os documentos são devolvidos:
Model.aggregate(
    [
        // Match the document containing the array element
        { "$match": { "comments._id" : oid } },

        // Unwind to "de-normalize" the array content
        { "$unwind": "$comments" },

        // Match the specific array element
        { "$match": { "comments._id" : oid } },

        // Group back and just return the "upvotes" field
        { "$group": {
            "_id": "$_id",
            "comments": { "$push": { "upvotes": "$comments.upvotes" } }
        }}
    ],
    function(err,docs) {


    }
);

Ou nas versões modernas do MongoDB desde 2.6 você pode até fazer isso:
Model.aggregate(
    [
        { "$match": { "comments._id" : oid } },
        { "$project": {
            "comments": {
                "$setDifference": [
                    { "$map": {
                        "input": "$comments",
                        "as": "el",
                        "in": {
                            "$cond": [
                                { "$eq": [ "$$el._id", oid ] },
                                { "upvotes": "$$el.upvotes" },
                                false
                            ]
                        }
                    }},
                    [false]
                ]
            }}
        }}
    ],
    function(err,docs) {

    }
)

E isso usa o $map e $setDifference operadores façam uma filtragem "in-line" do conteúdo do array sem primeiro processar um $unwind palco.

Portanto, se você deseja mais controle sobre como o documento é retornado, a estrutura de agregação é a maneira de fazer isso ao trabalhar com documentos incorporados.