MongoDB-有条件地匹配两个数组
存在以下对象数组:MongoDB-有条件地匹配两个数组,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,存在以下对象数组: let externalArray = [ { name: "xxx", max: 100, unit: "myUnit" }, { name: "yyy", max: 90, unit: "myUnit" } ] 以及以下mongodb结构: [ { "myList": [ { "name": "xxx", "amount":
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所对应的对象,因为您要将输入数组与文档中的数组进行比较,所以除了执行
$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" } }
}
])
测试:
注意:
在答复中:
myList
数组将只包含来自externalArray
的匹配对象myList
不存在,或者myList
和externalArray
之间不存在匹配对象,则不会看到文档(因此,两个数组之间应该至少有一个匹配对象才能取出文档)在将外部数组传递到聚合管道之前,可以将其转换为以下结构并用作条件 我们可以在
$match
表达式中使用它来匹配至少有一个匹配项的文档
[{
"name": "xxx",
"amount": {
"$lte": 100
},
"unit": "myUnit"
},
{
"name": "yyy",
"amount": {
"$lte": 90
},
"unit": "myUnit"
}]
/*示例js实现*/
const matchConditions=externalArray.map({name,max,unit})=>({
名称
金额:{$lte:max},
单元
}))
我们可以在$filter
条件中使用以下内容
[{
"$and": [
{ "$eq": ["name", "xxx"] },
{ "$lte" ["amount", 100 },
{ "$eq": ["unit", "myUnit"] }
]
},
{
"$and": [
{ "$eq": ["$$this.name", "yyy"] },
{ "$lte": ["$$this.amount", 90 },
{ "$eq": ["$$this.unit", "myUnit"] }
]
}]
最后,我们可以使用以下聚合
db.collection.aggregate([
{
$match: {
myList: {
$elemMatch: {
$or: matchConditions
}
}
}
},
{
$addFields: {
myList: {
$filter: {
input: '$myList',
cond: {
$or: filterConditions
}
}
}
}
}
])
不幸的是没有。。。当我尝试动态使用外部数组中的值时…这很有意义,非常感谢!它确实解决了我最初的问题,我将把你的答案标记为正确,但我刚刚意识到我的数据库结构中还有两个类似“myList”的列表。我要把它们全部解开,走同样的步骤吗?但最后我该如何把所有的东西组合起来呢?仅使用_id:“$\u id”似乎不起作用。@andfrst:哦,好的,通常数组和嵌套数组不仅在MongoDB中是一个问题,在编程语言中也是一个问题:-)如果在庞大的数据集上使用,即使这个查询也有点复杂(尝试在初始阶段过滤文档)!除非我们看到数据,否则我们什么都不能说。。也许你可以用示例数据(整个单据)和所需的o/p提出一个新问题-有人可以帮你查询..这是一个非常优雅的解决方案,谢谢。
db.collection.aggregate([
{
$match: {
myList: {
$elemMatch: {
$or: matchConditions
}
}
}
},
{
$addFields: {
myList: {
$filter: {
input: '$myList',
cond: {
$or: filterConditions
}
}
}
}
}
])