gpt4 book ai didi

javascript - Mongodb:如何返回查询列表中存在的数组元素

转载 作者:行者123 更新时间:2023-11-30 16:59:30 26 4
gpt4 key购买 nike

我有一个名为 shops 的集合。结构如下:

[
{
'_id' : id1,
'details' : {name: 'shopA'},
'products' : [{
_id: 'p1',
details: {
'name': 'product1'
}
},{
_id: 'p2',
details: {
'name': 'product2'
}
}, {
_id: 'p4',
details: {
'name': 'product4'
}
}
},{
'_id' : id2,
'details' : {name: 'shopB'},
'products' : [{
_id: 'p1',
details: {
'name': 'product1'
}
},{
_id: 'p4',
details: {
'name': 'product4'
}
}, {
_id: 'p5',
details: {
'name': 'product5'
}
}
},{
'_id' : id3,
'details' : {name: 'shopC'},
'products' : [{
_id: 'p1',
details: {
'name': 'product1'
}
},{
_id: 'p2',
details: {
'name': 'product2'
}
}, {
_id: 'p3',
details: {
'name': 'product3'
}
}
},{
'_id' : id4,
'details' : {name: 'shopOther'},
'products' : [{
_id: 'p10',
details: {
'name': 'product10'
}
},{
_id: 'p12',
details: {
'name': 'product12'
}
}, {
_id: 'p13',
details: {
'name': 'product13'
}
}
}
]

现在用户可以从菜单中选择一些产品并尝试为这些产品找到商店。结果应该是提供至少一种所选商品的所有商店。

例子,

假设用户选择 ['p1', 'p2', 'p3']//ids然后只有三个店id1、id2、id3 将被列出(id4 没有这些项目),加上结构是这样的,它从结果数组的文档中删除商店的其余产品(未列出)。

有没有办法,我可以直接从 mongodb 得到这样的结果?

最佳答案

既然你问得很好而且格式也很好,那么考虑到类似的答案可能实际上不适合引用,特别是如果你对 MongoDB 产品的经验水平很低。

类似 $redact 的选项可能看起来很简单,而且它们通常很适合。但这不是您需要如何构建语句的情况:

db.collection.aggregate([
{ "$match": { "products._id": { "$in": ["p1","p2","p3"] } }},
{ "$redact": {
"$cond": {
"if": {
"$or": [
{ "$eq": [ "$_id", "p1" ] },
{ "$eq": [ "$_id", "p2" ] },
{ "$eq": [ "$_id", "p3" ] }
]
},
"then": "$$DESCEND",
"else": "$$PRUNE"
}
}}
])

这适用于“不太明显”使用 $or在聚合运算符中。至少在语法和形式上是正确的,但实际上是“彻底失败”。原因是因为 $redact 通常是一个“递归”操作,它检查文档的“所有级别”,而不仅仅是特定级别。因此,您在“顶级”中的 _id 断言将失败,因为同名的顶级字段将不匹配该条件。

关于这个你真的没有什么可以做的,但是考虑到数组中的 _id 实际上是一个“唯一”元素,那么你总是可以在 $project 中执行这个操作。在$map的帮助下上台和 $setDifference :

db.collection.aggregate([
{ "$match": { "products._id": { "$in": ["p1","p2","p3"] } }},
{ "$project": {
"details": 1,
"products": {
"$setDifference": [
{ "$map": {
"input": "$products",
"as": "el",
"in": {
"$cond": {
"if": {
"$or": [
{ "$eq": [ "$$el._id", "p1" ] },
{ "$eq": [ "$$el._id", "p2" ] },
{ "$eq": [ "$$el._id", "p3" ] }
]
},
"then": "$$el",
"else": false
}
}
}},
[false]
]
}
}}
])

看似冗长,其实效率很高。 $map 运算符为每个文档“内联”处理数组,并作用于每个元素以生成一个新数组。在 $cond 下做出的 false 断言在条件不匹配的情况下,通过考虑与 $setDifference 比较的结果“集”来平衡,这有效地“过滤”了结果数组中的 false 结果,只留下有效的匹配项。

当然,如果 _id 值或整个对象不是真正的“唯一”,那么“集合”将不再有效。考虑到这一点,以及提到的运算符对于 2.6 之前的 MongoDB 版本不可用的事实,那么更传统的方法是 $unwind。数组成员,然后通过 $match“过滤”它们操作。

db.collection.aggregate([
{ "$match": { "products._id": { "$in": ["p1","p2","p3"] } }},
{ "$unwind": "$products" },
{ "$match": { "products._id": { "$in": ["p1","p2","p3"] } }},
{ "$group": {
"_id": "$_id",
"details": { "$first": "$details" },
"products": { "$push": "$products" }
}}
])

考虑到根据其他示例,$match 阶段应该首先在管道中执行,以减少匹配条件的“可能”文档。 $match 的“第二”阶段在“非规范化”形式时对数组内的文档元素进行实际“过滤”。

由于数组被$unwind“解构”了,所以$group的目的就是“重新构建”数组,“过滤”掉不符合条件的元素。

MongoDB 还提供了 positional $运算符以便从查询条件中选择匹配的数组元素。像这样:

db.collection.find(
{ "products._id": { "$in": ["p1","p2","p3"] },
{ "details": 1, "products.$": 1 }
)

但这里的问题是这个运算符只支持查询文档中提供的条件的“第一个”匹配。这是一种设计意图,目前还没有严格的运算符语法来满足多个匹配项的需求。

因此您目前的 final方法是使用 .aggregate()方法,以便实际实现您想要的内部数组的匹配过滤。要么过滤内容,要么在客户端代码中自行响应,具体取决于您最终的接受程度。

关于javascript - Mongodb:如何返回查询列表中存在的数组元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29139408/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com