给定具有以下结构的文档:
{ 'id': 1, name: 'bob', type: 'foo', children: [{'id': 2}, {'id': 3}]}
{ 'id': 2, name: 'bob', type: 'foo' }
{ 'id': 3, name: 'bob', type: 'bar' }
{ 'id': 4, name: 'bob', type: 'foo', children: [{'id': 5}, {'id': 6}]}
{ 'id': 5, name: 'bob', type: 'foo' }
{ 'id': 6, name: 'bob', type: 'foo' }
我如何编写聚合管道查询来查找所有文档,如果这些文档有子文档,则所有子文档的类型都是foo
(父文档的类型是"foo"(?
附加说明:
children
是一个对象数组,其属性引用同一集合中的其他文档- 并非所有文档都有子级
- 更改文档结构不是一个选项
- 我已经研究了$unvent和$lookup,但这会导致许多文档,我只想在文档末尾使用父文档
在对聚合管道API进行了一些额外的处理之后,这里有一个潜在的解决方案。
步骤是:
- 基于
type
标准的第一个$match
,以确保随后在管道中只使用具有适当type
的父文档 - 对子文档执行简单的
$lookup
。虽然这似乎没有明确记录,但$lookup
可以毫无困难地使用数组中嵌套对象的属性 - 对生成的文档进行最终匹配,使用
$elemMatch
和一些否定来达到预期效果
以下是使用Robo3T的情况(应该很容易翻译到其他查询客户端(:
注意:在这种特殊情况下,id
只是连接文档的占位符,而不是";官方的";_id
mongo字段
db.getCollection('items').aggregate([
{ $match : { "type": "foo" } },
{
$lookup: {
from: "items",
localField: "children.id",
foreignField: "id",
as: "items"
}
},
{
$match : {
"items": {
$not: {
$elemMatch: {
"type": { $ne: "foo" }
}
}
}
}
}
])
这将排除文件1和3;条";并且1包括它
这可能不是一个最佳解决方案,我还没有在大型数据集上进行过测试。此外,使用$elemMatch
的最后一场比赛相当混乱,因此欢迎提出改进建议。
我已经编写了一个解决方案。请看一下查询。解决方案检查链接:https://mongoplayground.net/p/cu7Mf8XZHDI
该查询类似于以下问题:MongoDB(Mongoose(如何使用$elematch 返回所有文档字段
db.collection.find({},
{
students: {
$filter: {
input: "$students",
as: "student",
cond: {
$or: [
{
$eq: [
"$$student.age",
8
]
},
{
$eq: [
"$$student.age",
15
]
}
]
}
}
}
})