sql >> Base de Datos >  >> NoSQL >> MongoDB

Mongoose selecciona campos de subdoc.

Así es como MongoDB maneja la proyección básica con elementos de matriz. Si bien puedes hacer algo como esto:

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

})

Y eso solo devolvería el campo "votos a favor" desde dentro de los subdocumentos de la matriz de comentarios para todos los documentos que coincidan con la condición y todos los elementos de la matriz, por supuesto, no puede combinar esto con una proyección posicional seleccionada usando posicional $ operador. Esto básicamente se deriva de la "teoría" que generalmente en realidad desea devolver toda la matriz. Así es como ha funcionado siempre y no es probable que cambie pronto.

Para obtener lo que desea, necesita las capacidades extendidas para la manipulación de documentos que ofrece marco de agregación . Esto le da más control sobre cómo se devuelven los documentos:

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


    }
);

O en las versiones modernas de MongoDB desde 2.6, incluso puede hacer esto:

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

    }
)

Y eso usa el $map y $setDifference operadores para realizar un filtrado "en línea" del contenido de la matriz sin procesar primero un $unwind escenario.

Entonces, si desea tener más control sobre cómo se devuelve el documento, entonces el marco de agregación es la forma de hacerlo cuando se trabaja con documentos incrustados.