web-dev-qa-db-ja.com

Mongoose:集計を使用して一緒に検索する方法

Mongooseで aggregatefindを一緒に使用するにはどうすればよいですか?
i.e次のスキーマがあります。

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)

nameおよびfollowers_countフィールドのみでユーザーにクエリを実行するにはどうすればよいですか。
followers_countfollowersの長さ。

そこで、 select を使用してフィールドnameのみを取得できることを知っています。
followersのカウントを取得するにはどうすればよいですか?

21
Colin Witkamp

MongoDB 3.6以降の場合、$expr演算子を使用して、クエリ言語内で集計式を使用できるようにします。

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

互換性のないバージョンでは、$match$redactコレクションを照会するパイプライン。たとえば、名前が 'development'でfollowers_countが30より大きいlocationsコレクションを照会する場合は、次の集約操作を実行します。

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);
})

または単一のパイプライン内で

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);
})

上記は、ユーザーからの_id参照のみを含む場所を返します。フォロワー配列を「取り込む」手段としてユーザー文書を返すために、$lookupパイプラインを追加できます。


基礎となるMongoサーバーのバージョンが3.4以降の場合、次のようにパイプラインを実行できます。

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);
})

それ以外の場合は、$unwindフォロワー配列を適用する前に$lookupその後、$groupパイプラインで再グループ化:

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

次のように使用できます。

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

試合では次のようなことができます:

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

プロジェクトでは、次のような数字0または1を使用して、必要なフィールドを選択できます。

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

0は置く、入れない、1は置くことを意味します。

10
israel.zinc