我在一个集合中有以下文档:
[{
id: 1,
name: 'My document 1',
allItems: [{
id: 'item1',
name: 'My item 1'
}, {
id: 'item2',
name: 'My item 2'
}, {
id: 'item3'
name: 'My item 3'
}],
containers: [{
id: 'container1',
selectedItems: [
'item3',
'item1'
]
}, {
id: 'container2',
selectedItems: [
'item3'
]
}]
},
...]
我现在想编写一个查询来查找具有特定容器 ID(即 container1
)的文档并将其返回,同时将其转换为 selectedItems
数组来保存 allItems
中的实际对象值同一文档的数组。我想得到这个文件:
{
id: 1,
name: 'My document 1',
container: {
id: 'container1',
selectedItems: [{
id: 'item3'
name: 'My item 3'
}, {
id: 'item1',
name: 'My item 1'
}
}
}
目前我有以下聚合(Node.js):db.collection.aggregate([{
$match: {'containers.id': 'container1'},
$addFields: {
container: {
$filter: {
input: '$containers',
as: 'container',
cond: {
$eq: ['$$container.id', 'container1']
}
}
}
},
$project: {containers: 0},
$unwind: {path: '$container'}
// I now have a new property "container" with the correct subdocument from the array
// and removed the original array with all containers.
// I now need a stage here to populate the container subdocuments in the `selectedItems` array
$project: {allItems: 0} // remove the list of all items when not needed anymore in a following stage
}]);
我知道有$lookup
,但由于我想从同一个文档(不是不同的集合)中填充匹配的数组项,我想我不需要它。即使在 $lookup
中指定相同的集合,它将使用我的集合的根文档填充数组,并且展开和匹配子文档所需的属性将变得非常复杂。我想过自己做一个
items
集合,但我需要在那里进行较慢的查找,并且我的数据不需要具有这些关系。我希望我的问题很清楚,我很感谢我能得到的任何帮助!
我正在对我的真实数据进行一些额外的转换,比如从原始根文档中复制一些属性并隐藏其他属性,但这并不重要。
再次感谢你!
最佳答案
$match
您的条件$filter
迭代 containers
的循环数组和过滤器id
$arrayElemAt
从上面的过滤结果中选择第一个元素$let
声明一个变量并存储上述过程并存储结果$filter
迭代 allItems
的循环根据上述结果排列和过滤项目db.collection.aggregate([
{ $match: { "containers.id": "container1" } },
{
$project: {
name: 1,
container: {
$let: {
vars: {
container: {
$arrayElemAt: [
{
$filter: {
input: "$containers",
cond: { $eq: ["$$this.id", "container1"] }
}
},
0
]
}
},
in: {
id: "$$container.id",
selectedItems: {
$filter: {
input: "$allItems",
cond: { $in: ["$$this.id", "$$container.selectedItems"] }
}
}
}
}
}
}
}
])
Playground第二个版本,你可以分阶段做流程,
$match
您的条件$filter
迭代 containers
的循环数组和过滤器id
$arrayElemAt
从上面的过滤结果中选择第一个元素$filter
迭代 allItems
的循环通过 selectedItems
排列和过滤项目$$REMOVE
将删除字段 db.collection.aggregate([
{ $match: { "containers.id": "container1" } },
{
$addFields: {
containers: "$$REMOVE",
container: {
$arrayElemAt: [
{
$filter: {
input: "$containers",
cond: { $eq: ["$$this.id", "container1"] }
}
},
0
]
}
}
},
{
$addFields: {
allItems: "$$REMOVE",
"container.selectedItems": {
$filter: {
input: "$allItems",
cond: { $in: ["$$this.id", "$container.selectedItems"] }
}
}
}
}
])
Playground
关于javascript - MongoDB聚合: Replacing an array of IDs with the corresponding objects from an array in the same document,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68833646/