如何在 MongoDB 请求中获取父母和父母的兄弟姐妹

Gou*_*pil 5 graph mongodb node.js

在 MongoDB/NodeJS 项目中,我已经对集合的元素进行了排序,就像家谱一样。在特定路线中,我试图获取元素的父元素,以及父元素的兄弟元素,具有给定的深度,如下图所示:

收集树,通过请求想要的项目

在集合中,对于每个项目,我存储其他数据:

  • 父ID
  • 祖父 ID
  • isRoot(布尔值)

我试图用GraphLookup做一些事情,基于我的请求链接parentIdgrandParentId,像这样:

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 }
    }}
])
Run Code Online (Sandbox Code Playgroud)

它工作得很好,但问题是它无法检索没有parentId. 我已经考虑过做两个单独的视图,每个视图都包含一个 a GraphLookup(一个基于parentId/ grandParentId,另一个基于id/ parentId),然后在删除重复项的同时合并两个视图,但是为了获得根而执行两个潜在的大请求看起来很奇怪元素。

我想找到一个可靠的解决方案,因为我计划允许一个项目有多个父项。

abo*_*doa 2

您可以将其更改为多个步骤:

  1. 查找直系祖先数组(父母、祖父母等)
  2. 找到每个祖父母和“更高”的直系后代(从而为您提供父母兄弟姐妹、祖父母兄弟姐妹等)
  3. 将两个数组合并为一个集合(从而确保唯一性)
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"]}
    }}
])
Run Code Online (Sandbox Code Playgroud)

有关 .请参阅如何在组内推送多个列的值$setUnion

原答案:

如果您只对父级和父级的兄弟姐妹感兴趣,则可以使用 stage$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'
    }}
])
Run Code Online (Sandbox Code Playgroud)

这样,您的根元素仍应由$match中的第一部分找到pipeline

请注意,我$ifNull在第二部分中使用过滤掉“根”元素,因为在查找深度为 1 的元素时, $parentIdand$$grandparentId将为 null 或未定义。如果预期行为是应在任何深度 1 中找到所有根元素元素(如果根元素被视为兄弟元素),那么您可以摆脱它并简单地进行比较$parentId$$grandparentId直接比较。

查找文档:https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/