有以下对象数组:
let externalArray =
[
{ name: "xxx",
max: 100,
unit: "myUnit"
},
{ name: "yyy",
max: 90,
unit: "myUnit"
}
]
以及以下mongodb结构:
[
{
"myList": [
{
"name": "xxx",
"amount": 66.3,
"unit": "myUnit"
},
{
"name": "yyy",
"amount": 11.6,
"unit": "myUnit"
},
{
"name": "zzz",
"amount": 6.9,
"unit": "myUnit"
}
]
}
]
如何在聚合中使用$ match查询来仅输出myList.amount <= externalArray.max和myList.unit等于同名externalArray.unit的对象?非常感谢您的帮助。
答案 0 :(得分:1)
由于您正在将输入数组与文档中的数组进行比较,因此您需要与$filter
一起做更多的事情:
db.collection.aggregate([
/** Unwind (Split array into objects :: total docs = each doc * no.of objects in array of respective doc) */
{
$unwind: "$myList"
},
/** Iterate on input `externalArray` & check for all conditions. Creates an array field `matches` */
{
$addFields: {
matches: {
$filter: {
input: externalArray,
cond: {
$and: [ { $eq: [ "$$this.name", "$myList.name" ] },
{ $eq: [ "$$this.unit", "$myList.unit" ] },
{ $lte: [ "$myList.amount", "$$this.max" ] }
]
}
}
}
}
},
/** In filter step if it matches with any condition then `matches` will have 1 or more objects from `externalArray`
* Excluding all docs where there is no match */
{
$match: { matches: { $ne: [] } }
},
/** Remove unnecessary field */
{
$project: { matches: 0 }
},
/** Since we unwind the array - group back all docs based on `_id` */
{
$group: { _id: "$_id", myList: { $push: "$myList" } }
}
])
测试: mongoplayground
注意:
在回复中:
myList
数组将仅包含来自externalArray
的匹配对象。myList
不存在或myList
和externalArray
之间不存在匹配对象的文档(因此,两个数组之间至少应有一个匹配对象)以便将文档取出来。)答案 1 :(得分:0)
您可以在将外部数组传递到聚合管道之前对其进行转换,使其具有以下结构并用作条件。
我们可以在$match
表达式中使用它来匹配具有至少一个匹配项的文档。
[{
"name": "xxx",
"amount": {
"$lte": 100
},
"unit": "myUnit"
},
{
"name": "yyy",
"amount": {
"$lte": 90
},
"unit": "myUnit"
}]
/* example js implementation */
const matchConditions = externalArray.map(({ name, max, unit })=> ({
name,
amount: { $lte: max },
unit
}))
我们可以在$filter
条件下使用以下内容
[{
"$and": [
{ "$eq": ["name", "xxx"] },
{ "$lte" ["amount", 100 },
{ "$eq": ["unit", "myUnit"] }
]
},
{
"$and": [
{ "$eq": ["$$this.name", "yyy"] },
{ "$lte": ["$$this.amount", 90 },
{ "$eq": ["$$this.unit", "myUnit"] }
]
}]
/* example js implementation */
const filterConditions = externalArray.map(({ name, max, unit }) => ({
$and: [
{ $eq: ['$$this.name', name] },
{ $lte: ['$$this.amount', max },
{ $eq: ['$$this.unit', unit] }
]
}))
然后最后我们可以使用以下聚合
db.collection.aggregate([
{
$match: {
myList: {
$elemMatch: {
$or: matchConditions
}
}
}
},
{
$addFields: {
myList: {
$filter: {
input: '$myList',
cond: {
$or: filterConditions
}
}
}
}
}
])