$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
]}
]
}
}
}}
我想过滤 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
]}
]
}
}
}}