web-dev-qa-db-fra.com

Mongoose: comment utiliser l'agrégat et trouver ensemble

Comment puis-je utiliser agrégat et find ensemble dans Mongoose?
C'est-à-dire que j'ai le schéma suivant:

const schema = new Mongoose.Schema({
  created: { type: Date, default: Date.now() },
  name: { type: String, default: 'development' }
  followers: [{ type: Mongoose.Schema.ObjectId, ref: 'Users'}]
...
})

export default Mongoose.model('Locations', schema)

Comment interroger les utilisateurs uniquement avec les champs name et followers_count.
followers_count: la longueur de followers.

Là, je sais que nous pouvons utiliser select pour obtenir uniquement le champ name.
Comment pouvons-nous obtenir le nombre de followers?

21
Colin Witkamp

Pour MongoDB 3.6 et versions ultérieures, utilisez le $expr opérateur permettant d’utiliser des expressions d’agrégation dans le langage de requête:

var followers_count = 30;
db.locations.find({
   "$expr": { 
       "$and": [
           { "$eq": ["$name", "development"] },
           { "$gte": [{ "$size": "$followers" }, followers_count ]}
       ]
    }
});

Pour les versions non compatibles, vous pouvez utiliser à la fois le $match et $redact des pipelines pour interroger votre collection. Par exemple, si vous souhaitez interroger la collection locations où le nom est 'développement' et followers_count est supérieur à 30, exécutez l'opération d'agrégation suivante:

const followers_count = 30;
Locations.aggregate([
    { "$match": { "name": "development" } },
    {
        "$redact": {
            "$cond": [
                { "$gte": [ { "$size": "$followers" }, followers_count ] },
                "$$KEEP",
                "$$Prune"
            ]
        }
    }
]).exec((err, locations) => {
    if (err) throw err;
    console.log(locations);
})

ou dans un seul pipeline comme

Locations.aggregate([
    {
        "$redact": {
            "$cond": [
                { 
                    "$and": [
                        { "$eq": ["$name", "development"] },
                        { "$gte": [ { "$size": "$followers" }, followers_count ] }
                     ]
                },
                "$$KEEP",
                "$$Prune"
            ]
        }
    }
]).exec((err, locations) => {
    if (err) throw err;
    console.log(locations);
})

Ce qui précède renverra les emplacements avec uniquement le _id références des utilisateurs. Pour retourner les documents de l'utilisateur comme moyen de "peupler" le tableau de followers, vous pouvez ensuite ajouter le $lookup pipeline.


Si la version de serveur Mongo sous-jacente est 3.4 et plus récente, vous pouvez exécuter le pipeline en tant que

let followers_count = 30;
Locations.aggregate([
    { "$match": { "name": "development" } },
    {
        "$redact": {
            "$cond": [
                { "$gte": [ { "$size": "$followers" }, followers_count ] },
                "$$KEEP",
                "$$Prune"
            ]
        }
    },
    {
        "$lookup": {
            "from": "users",
            "localField": "followers",
            "foreignField": "_id",
            "as": "followers"
        }
    }
]).exec((err, locations) => {
    if (err) throw err;
    console.log(locations);
})

sinon vous auriez besoin de $unwind le tableau des adeptes avant d’appliquer $lookup puis regrouper avec $group pipeline après cela:

let followers_count = 30;
Locations.aggregate([
    { "$match": { "name": "development" } },
    {
        "$redact": {
            "$cond": [
                { "$gte": [ { "$size": "$followers" }, followers_count ] },
                "$$KEEP",
                "$$Prune"
            ]
        }
    },
    { "$unwind": "$followers" },
    {
        "$lookup": {
            "from": "users",
            "localField": "followers",
            "foreignField": "_id",
            "as": "follower"
        }
    },
    { "$unwind": "$follower" },
    {
        "$group": {
            "_id": "$_id",
            "created": { "$first": "$created" },
            "name": { "$first": "$name" },
            "followers": { "$Push": "$follower" }
        }
    }
]).exec((err, locations) => {
    if (err) throw err;
    console.log(locations);
})
23
chridam

Vous pouvez utiliser comme suit:

db.locations.aggregate([
  {$match:{"your find query"}},
  {$project:{"your desired fields"}}
])

Dans le match, vous pouvez faire des choses comme:

{{$match:{name:"whatever"}}

Dans le projet, vous pouvez sélectionner les champs souhaités en utilisant les chiffres 0 ou 1, comme suit:

{$project:{_id:1,created:0,name:1}}

Quel 0 signifie, ne pas mettre et 1 signifie mettre.

10
israel.zinc