node.js - 如何在 MongoDB 请求中获取 parent 和 parent 的 sibling

标签 node.js mongodb graph

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

Collection tree, items wanted through the request

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

  • parentId
  • 祖父 ID
  • isRoot( bool 值)

  • 我试图用 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 }
        }}
    ])
    

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

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

    最佳答案

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

  • 查找直系祖先( parent 、祖 parent 等)的数组
  • 查找每个祖 parent 和“更高”的直系后代(从而为您提供 parent sibling 、祖 parent sibling 等)
  • 将两个数组合并为一个集合(从而确保唯一性)
  • 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/

    相关文章:

    algorithm - 来自给定节点的最长路径近似算法

    node.js - 参数覆盖静态路由的快速路由

    node.js - npm 安装失败。云9IDE

    javascript - 尝试为我的 nodejs Controller 编写我的第一个 "global"函数

    javascript - 无法构建 Flux todo-mvc 示例

    mongodb - 如何使用 mgo 从文档中解码命名类型别名?

    javascript - MongoDB javascript 传递参数

    java - MongoDB 复杂存储过程可以与 Java Web 服务一起使用吗

    algorithm - 将学生分成两组的图算法

    algorithm - 在图中获取下一个最近邻居的最佳方法是什么?