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

Mongoose seleziona i campi del sottodoc

Questo è il modo in cui MongoDB gestisce la proiezione di base con elementi di array. Mentre puoi fare qualcosa del genere:

Model.findOne({}, { "comments.upvotes": 1 },function(err,doc) {

})

E ciò restituirebbe semplicemente il campo "voti positivi" dall'interno dei documenti secondari dell'array dei commenti per tutti i documenti che soddisfano la condizione e tutti gli elementi dell'array, ovviamente, non puoi combinarlo con una proiezione posizionale selezionata usando posizionale $ operatore. Questo fondamentalmente deriva dalla "teoria" che generalmente in realtà vuoi restituire l'intero array. Quindi è così che ha sempre funzionato e non è probabile che cambi presto.

Per ottenere ciò che desideri, hai bisogno delle funzionalità estese per la manipolazione dei documenti offerte da struttura di aggregazione . Questo ti dà un maggiore controllo su come vengono restituiti i documenti:

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) {


    }
);

Oppure nelle versioni moderne di MongoDB dalla 2.6 puoi anche farlo:

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 questo utilizza $map e $setDifference operatori per eseguire un filtraggio "in linea" del contenuto dell'array senza prima elaborare un $unwind fase.

Quindi, se desideri un maggiore controllo su come viene restituito il documento, il framework di aggregazione è il modo per farlo quando lavori con i documenti incorporati.