Getting ancestors in MongoDb using tree structure

|▌冷眼眸甩不掉的悲伤 提交于 2021-01-01 12:56:23

问题


I have the following collection representing the directory structure.

I'd like to write an aggregation query that will return all child directory IDs starting from a certain point.

For example:

  • Starting from root: results: child_A, child_B, child_A_1

  • Starting from child_a: results: child_A_1

I've created the following query (in Mongo 4.2) according to the docs, but I'm unable to run it successfully.

[{
    $match: {
        _id: ObjectId('5de7a00bf3663d0805644b91')
    }
}, {
    $graphLookup: {
        from: 'documents',
        startWith: '$_id',
        connectFromField: '_id',
        connectToField: 'parentId',
        as: 'hierarchy'
    }
}]

How can I solve that issue?


回答1:


It is non-trivial solution.

REQUIREMENTS

1 We need to add extra field (let's call it level) which indicates where document is located inside hierarchy.

|root        0
|-child A    1
|--child A_1 2
|-child B    1

2 We need to define previously hierarchy depth (for instance: max 3)

LIMITATION

In order to filter from specific level, we need to modify root and children $match values.

Ensure always hierarchy level:

root     - 0
children - 1

root     - 1
children - 2  

SOLUTION

db.documents.aggregate([
  {
    $facet: {
      root: [
        {
          $match: {
            level: 0
          }
        }
      ],
      children: [
        {
          $match: {
            level: 1
          }
        },
        {
          $graphLookup: {
            from: "documents",
            startWith: "$_id",
            connectFromField: "_id",
            connectToField: "parentId",
            maxDepth: 0,
            as: "hierarchy"
          }
        },
        {
          $sort: {
            _id: 1
          }
        }
      ]
    }
  },
  {
    $unwind: "$root"
  },
  {
    $project: {
      "root._id": 1,
      "root.name": 1,
      "root.level": 1,
      "root.hierarchy": {
        $filter: {
          input: "$children",
          as: "sub_level",
          cond: {
            $eq: [
              "$$sub_level.parentId",
              "$root._id"
            ]
          }
        }
      }
    }
  },
  {
    $replaceRoot: {
      newRoot: "$root"
    }
  }
])

MongoPlayground (max depth: 3) | MongoPlayground (max depth: 4)

EXPLANATION

  1. With $facet we define level structure. root all root directory only. children contains all children with level 1 + children descendants.

  2. We $filter (merge) root and children by parentId

  3. With $project and $replaceRoot we return original structure.

LINKS

https://docs.mongodb.com/manual/reference/operator/aggregation/facet/
https://docs.mongodb.com/manual/reference/operator/aggregation/filter/
https://docs.mongodb.com/manual/reference/operator/aggregation/replaceRoot/



来源:https://stackoverflow.com/questions/59245431/getting-ancestors-in-mongodb-using-tree-structure

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!