mongo中是否存在,通过MapReduce或Aggregation来应用基于第一个?的结果集的第二个查询,例如聚合中的聚合,或MapReduce中的新发射/查询。
例如,我有一个物化的物化路径模式(也包括parentId),我可以简单地通过以下方式得到所有的根:
db.collection.find({parentId: null}
.toArray(function(err, docs) {
});
我想要做的是确定这些文档是否有子项,只是标记true/false
。我可以使用异步each
迭代这些文档并检查,但是在大文档上,这根本不是很高效并导致事件循环延迟,我可以使用eachSeries
,但这只是很慢。 / p>
理想情况下,我希望能够在Mongo中处理这一切。如果可能的话,有什么建议吗?
编辑,示例集合:
{
_id: 1,
parentId: null,
name: 'A Root Node',
path: ''
}
{
_id: 2,
parentId: 1,
name: 'Child Node A',
path: ',1'
}
{
_id: 3,
parentId: 2,
name: 'Child Node B',
path: ',1,2'
}
{
_id: 4,
parentId: null,
name: 'Another Root Node',
path: ''
}
这基本上代表两个根节点,其中一个根节点({_id: 1}
)有两个子节点(一个是直接节点),例如:
我想做的是根据parentId
进行查询,以便我可以使用null
或通过传递parentId
来获取根节点我可以获得该节点的子节点并确定是否从中得出结果集,任何项目都包含子项,示例响应为{parentId: null}
:
[{
_id: 1,
parentId: null,
name: 'A Root Node',
path '',
hasChildren: true
},
{
_id: 4,
parentId: null,
name: 'Another Root Node',
path '',
hasChildren: false
}]
答案 0 :(得分:0)
您可以尝试从物化路径创建parentIds数组,然后可以在聚合管道中使用它来投影额外的字段/标记hasChildren
。
这可以通过在 map()
方法返回的光标上使用 find()
方法来完成。以下说明了这一点:
var arr = db.collection.find({ "parentId": { "$ne": null } })
.map(function (e){ return e.path; })
.join('')
.split(',')
.filter(function (e){ return e; })
.map(function (e){ return parseInt(e); }),
parentsIds = _.uniq(arr); /* using lodash uniq method to return a unique array */
使用这个parentIds数组,您可以使用聚合框架,尤其是 $project
管道,该管道使用 set operator $setIsSubset
,它接受两个数组,当第一个数组是第二个数组的子集时返回true,包括第一个数组等于第二个数组时,否则返回false:
db.collection.aggregate([
{
"$match": {
"parentId": null
}
},
{
"$project": {
"parentId": 1,
"name": 1,
"path": 1,
"hasChildren": { "$setIsSubset": [ [ "$_id" ], parentIds ] }
}
}
], function (err, res) { console.log(res); });