$filter 嵌套级别与 $or, $gte, $lte 运算符

$filter nested level with $or, $gte, $lte operators

我想过滤 MONGO 数据库中的多嵌套文档

示例 JSON:

{ 
"_id" : ObjectId("5b5c3afbcc43cb5ed64b7a04"), 
"id" : NumberLong(15015060), 
"name" : "1801_Conf", 
"type" : NumberInt(2), 
"members" : [
    {
        "id" : NumberLong(15015061), 
        "name" : "1801_Conf-W--", 
        "sku" : "1801_new", 
        "type" : NumberInt(1), 
        "parent_id" : NumberLong(15015060), 
        "available_qty" : NumberInt(10), 
        "on_hand_qty" : NumberInt(10), 
        "outgoing_qty" : NumberInt(0), 
        "incoming_qty" : NumberInt(0), 
        "shortage_qty" : NumberInt(0), 
        "product_warehouses" : [
            {
                "warehouse_id" : NumberLong(3), 
                "available_qty" : NumberInt(10), 
                "outgoing_qty" : NumberInt(0), 
                "incoming_qty" : NumberInt(0)
            },
            {
                "warehouse_id" : NumberLong(4), 
                "available_qty" : NumberInt(600), 
                "outgoing_qty" : NumberInt(0), 
                "incoming_qty" : NumberInt(0)
            }
        ], 
        ]
    } 
] 

}

预期输出:只想过滤 available_qty < 50 and > 10 and members.product_warehouses.available_qty < 50 and > 20 的成员(不是全部)

查询:

db.products.aggregate([{
   "$match": {
       "tenant_id": XXX,
       "type" : 2
   }
}, {
   "$project": {
       "name": 1,
       "sku": 1,
       "members": {
           "$filter": {
               "input": "$members",
               "as": "member",
               "cond": {

                       "$and": 
                        [
                            {
                               "$gte": ["$$member.product_warehouses.available_qty", 10]
                            }, 
                            {
                               "$lte": ["$$member.available_qty", 50]
                            },
                            {
                               "product_warehouses": {
                               "$elemMatch" : {

                                   }
                               }
                            }
                        ]

               }
           }
       }
   }
}])

错误::{"ok":0,"errmsg":"invalid operator '$elemMatch'","code":15999}:聚合失败

您需要先$filter the members array and at the same time you have to apply $filter to the product_warehouses array with looping over the filtered members array using $map聚合。

最后您需要将 cond$and, $gt and $eq 聚合运算符放在一起,这与您的 预期输出 条件相同。

db.collection.aggregate([
  { "$project": {
    "members": {
      "$filter": {
        "input": {
          "$map": {
            "input": "$members",
            "as": "member",
            "in": {
              "$mergeObjects": [
                "$$member",
                { "product_warehouses": {
                  "$filter": {
                    "input": "$$member.product_warehouses",
                    "as": "product",
                    "cond": {
                      "$or": [
                        { "$lt": ["$$product.available_qty", 50] },
                        { "$gt": ["$$product.available_qty", 20] }
                      ]
                    }
                  }
                }}
              ]
            }
          }
        },
        "as": "member",
        "cond": {
          "$or": [
            { "$lte": [ "$$member.available_qty", 50 ] },
            { "$gte": [ "$$member.available_qty", 10 ] }
          ]
        }
      }
    }
  }},
  { "$match": { "members": { "$ne": [] } } }
])

给它一个try

Try below query it works perfectly and properly tested

db.test.aggregate(

// Pipeline
[
    // Stage 1
    {
        $unwind: {
            path : "$members",
            includeArrayIndex : "arrayIndex", // optional
            preserveNullAndEmptyArrays : false // optional
        }
    },

    // Stage 2
    {
        $match: {
             $and: [ 

                   {"members.available_qty": {$gte:10}}, 
                   {"members.available_qty": {$lte:50}} 
                   ]
        }
    },

    // Stage 3
    {
        $project: {
            "_id" :1, 
            "id" :1, 
            "name" :1, 
            "type" :1, 
            "members" : {
                "id":1,
                "name" :1, 
                "sku" : 1, 
                "type" :1, 
                "parent_id" :1, 
                "available_qty" :1, 
                "on_hand_qty" :1, 
                "outgoing_qty" :1, 
                "incoming_qty" :1, 
                "shortage_qty" :1, 
                "product_warehouses": {
                            $filter: {
                                input: "$members.product_warehouses",
                                as: "item",
                                cond: {
                                  "$and": [
                                    { "$gte": [ "$$item.available_qty", 20] },
                                    { "$lte": [ "$$item.available_qty", 50 ] },
                                    ]
                                }
                            }
                        }

                },

        }
    },

    // Stage 4
    {
        $match: {
            "members.product_warehouses":{$ne: []}

        }
    },

    // Stage 5
    {
        $group: {
            _id:"$_id",
            "id" :{ $last: '$id' }, 
            "name" :{ $last: '$name' }, 
            "type" : { $last: '$type' }, 
            members: { $addToSet: "$members" }
        }
    },
],

);

据我了解,这是您需要的查询。

db.col.aggregate([
    {"$unwind" : "$members"},
    {"$match" : {"$and" : [{"members.available_qty" : {"$lt" : 50}},{"members.available_qty" : {"$gt" : 10}}]}},
    {"$match" : {"$and" : [{"members.product_warehouses.available_qty" : {"$lt" : 50}},{"members.product_warehouses.available_qty" : {"$gt" : 20}}]}},
    {"$group" : {"_id" : "$_id",
        "type" : {"$first" : "$type"},
        "name" : {"$first" : "$name"},
        "id" : {"$first" : "$id"},
        "members" : {"$addToSet" : "$members"}
        }
    }
]);

db.lo.aggregate([
{"$unwind" : "$members"},
{"$match" : {
    "$and" : [
        {"members.available_qty" : {"$lt" : 50}},
        {"members.available_qty" : {"$gt" : 10}}
        ]
    }
},
{"$match" : { 
    "members.product_warehouses": { 
        "$elemMatch":{ 
            "available_qty": { "$lt": 50 }, 
            "available_qty": { "$gt": 20 }
        } 
    } 
}},
{"$group" : {"_id" : "$_id",
    "type" : {"$first" : "$type"},
    "name" : {"$first" : "$name"},
    "id" : {"$first" : "$id"},
    "members" : {"$addToSet" : "$members"}
    }
}

]);

如果任何一个子文档符合以下条件 members.product_warehouses.available_qty > 20 且 members.product_warehouses.available_qty < 50 它将 return 整个 product_warehouses 数组,它和 $elemMatch 一样

您可以使用以下聚合查询。由于 $elemMatch$project 阶段不是有效运算符,您可以用 $filter, $size and $gt 比较替换该部分。

{"members":{
  "$filter":{
    "input":"$members",
    "cond":{
      "$and":[
        {"$gte":["$$this.available_qty",10]},
        {"$lte":["$$this.available_qty",50]},
        {"$gt":[
          {"$size":{
            "$filter":{
              "input":"$$this.product_warehouses",
              "cond":{
                "$and":[
                  {"$gte":["$$this.available_qty",20]},
                  {"$lte":["$$this.available_qty",50]}
                ]
              }
            }
          }},
          0
        ]}
      ]
    }
  }
}}