MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Mongoose sélectionne les champs de sous-doc

C'est ainsi que MongoDB gère la projection de base avec des éléments de tableau. Bien que vous puissiez faire quelque chose comme ceci :

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

})

Et cela renverrait simplement le champ "upvotes" à partir des sous-documents du tableau de commentaires pour tous les documents correspondant à la condition et tous les éléments du tableau bien sûr, vous ne pouvez pas combiner cela avec une projection positionnelle sélectionnée en utilisant le positionnel $ opérateur. Cela découle essentiellement de la "théorie" que généralement vous voulez en fait retourner le tableau entier. C'est donc ainsi que cela a toujours fonctionné et ne devrait pas changer de sitôt.

Afin d'obtenir ce que vous voulez, vous avez besoin des capacités étendues de manipulation de documents offertes par structure d'agrégation . Cela vous donne plus de contrôle sur la façon dont les documents sont renvoyés :

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 dans les versions modernes de MongoDB depuis la 2.6, vous pouvez même faire ceci :

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

    }
)

Et cela utilise le $map et $setDifference opérateurs pour effectuer un filtrage "en ligne" du contenu du tableau sans traiter au préalable un $unwind scène.

Donc, si vous voulez plus de contrôle sur la façon dont le document est renvoyé, le cadre d'agrégation est le moyen de le faire lorsque vous travaillez avec des documents intégrés.