在 MongoDB/NodeJS 项目中,我已经对集合的元素进行了排序,就像家谱一样。在特定 route ,我试图获取元素的父元素,以及父元素的兄弟元素,具有给定的深度,如下图所示:
在集合中,对于每个项目,我存储其他数据:
我试图用 GraphLookup 做一些事情,基于我的链接请求
parentId
至 grandParentId
, 像这样 :db.arguments.aggregate([
{$match: { _id: mongoose.Types.ObjectId(id) }},
,
{$graphLookup: {
from: 'arguments',
startWith: '$grandParentId',
connectFromField: 'grandParentId',
connectToField: 'parentId',
maxDepth: Number(parentsDepth),
as: 'parentsHierarchy',
depthField: 'depth',
restrictSearchWithMatch: { isDeleted: false }
}}
])
它工作得很好,但问题是它无法检索没有
parentId
的根元素。 .我想过做两个单独的 View ,每个 View 都包含一个
GraphLookup
(一个基于 parentId
/grandParentId
,另一个基于 id
/parentId
),然后在删除重复项的同时合并两个 View ,但是为了只获取根元素而执行两个潜在的大请求看起来很奇怪.我想找到一个可靠的解决方案,因为我计划允许一个项目有多个父项。
最佳答案
您可以将其更改为多个步骤:
db.arguments.aggregate([
{$match: { _id: mongoose.Types.ObjectId(id) }},
{$graphLookup: {
from: 'arguments',
startWith: '$parentId',
connectFromField: 'parentId',
connectToField: '_id',
maxDepth: Number(parentsDepth),
as: 'parentsHierarchy',
depthField: 'depth',
restrictSearchWithMatch: { isDeleted: false }
}},
{$unwind: "$parentsHierarchy"},
{$lookup: {
from: 'arguments',
let: { id: '$parentsHierarchy._id', depth: '$parentsHierarchy.depth' },
pipeline: [
{$match:{$expr:{
$and: [{
$eq: ['$$id', '$parentId']
},{
$gte: ["$$depth", 2]
}]
}}},
{$addFields:{
depth: {$sum: ["$$depth", -1]}
}}],
as: 'children'
}},
{$group:{
_id: "$_id",
parentsHierarchy: {$addToSet: "$parentsHierarchy"},
children: {$push: "$children"}
// The rest of your root fields will have to be added here (someField: {$first: "$someField"})
}},
{$addFields:{
hierarchy: {$setUnion: ["$children", "$parentsHierarchy"]}
}}
])
见 How to push multiple columns' value within group关于
$setUnion
.原答案:
如果你只对 parent 和 parent 的 sibling 感兴趣,你可以使用
$lookup
舞台代替 $graphLookup
,因为您不需要图形给您的递归。您的
$lookup
可以这样做:db.test.aggregate([
{$lookup: {
from: 'arguments',
let: { parentId: '$parentId', grandParentId: '$grandParentId' },
pipeline: [{$match:{$expr:{
$or: [{
$eq: ['$_id', '$$parentId']
},{
$eq: [{$ifNull: ['$parentId', 'xyz']}, '$$grandParentId']
}]
}}}],
as: 'parentsAndTheirSiblings'
}}
])
这样你的根元素应该仍然可以被
$match
的第一部分找到。在 pipeline
.请注意,我正在使用
$ifNull
在第二部分过滤掉“根”元素,因为 $parentId
和 $$grandparentId
在查找深度为 1 的元素时,将为 null 或未定义。如果预期行为是应该为任何深度为 1 的元素找到所有根元素(如果根元素被视为兄弟元素),那么您可以摆脱它并简单地进行比较$parentId
和 $$grandparentId
直截了当。查找文档:https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/
关于node.js - 如何在 MongoDB 请求中获取 parent 和 parent 的 sibling ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61009278/