使用Express和Mongo使用递归表制作节点树

我正在使用 ExpressJS 和 Mongo 处理 REST api,并且我有一个包含 N 个级别的集合。

所以为了解决这个问题,我在 mongo 中使用了一个递归表(或集合),其中一个字段是 id,每个寄存器都有一个 parent_id,它与它的孩子处于同一级别。为了更好地解释这一点,这里是一个 ER 表示

因此,正如您所见,mongo 会像这样保存数据 json(帐户级别 0 的父级为 null)

[
  { "id": "45TYYU", "parent_id": null, "name":"account 1", "type": 1, "category": 1 },
  { "id": "45TYYXT", "parent_id": "45TYYU", "name":"account 2", "type": 1, "category": 1 },
  { "id": "45TYYPZ", "parent_id": "45TYYU", "name":"account 3", "type": 1, "category": 1 },
  { "id": "45TYYPZRE", "parent_id": "45TYYPZ", "name":"account 4", "type": 1, "category": 1 },
  { "id": "45TYYPZSX", "parent_id": "45TYYPZ", "name":"account 5", "type": 1, "category": 1 },
  { "id": "45TYYPZGP", "parent_id": "45TYYXT", "name":"account 6", "type": 1, "category": 1 }
]

账户 2 和账户 3 是账户 1 的孩子,而账户 4 和账户 5 是账户树的孩子,账户 6 是账户 2 的孩子……但每个寄存器都处于同一逻辑级别,仅通过 parent_id 进行标识。

所以我需要将这些数据转换为 GET 方法来重构它,如下所示:

[
    { 
        "id": "45TYYU",
        "parent_id": null,
        "name":"account 1",
        "type": 1,
        "category": 1,
        "children": [
            { 
                "id": "45TYYXT",
                "parent_id": "45TYYU",
                "name":"account 2",
                "type": 1,
                "category": 1,
                "children": [
                    { "id": "45TYYPZGP", "parent_id": "45TYYXT", "name":"account 6", "type": 1, "category": 1 }
                ]
            },
            { 
                "id": "45TYYPZ",
                "parent_id": "45TYYU",
                "name":"account 3",
                "type": 1,
                "category": 1,
                "children": [
                    { "id": "45TYYPZRE", "parent_id": "45TYYPZ", "name":"account 4", "type": 1, "category": 1 },
                    { "id": "45TYYPZSX", "parent_id": "45TYYPZ", "name":"account 5", "type": 1, "category": 1 }
                ]
            }
        ]
    },
    { 
        "id": "45TFJK",
        "parent_id": null,
        "name":"account 7",
        "type": 1,
        "category": 1,
        "children": [
            { 
                "id": "47HJJT",
                "parent_id": "45TFJK",
                "name":"account 8",
                "type": 1,
                "category": 1
            },
            { 
                "id": "47YHJU",
                "parent_id": "45TFJK",
                "name":"account 8",
                "type": 1,
                "category": 1
            }
        ]
    }
]

是的...父母级别 0 的 parent_id 为空,我想将它的孩子放在一个名为“children”的数组中,然后在 GET 响应中像这样发送到我的 UI

在 expressJS 中执行此操作的最佳方法是什么?是否有允许我这样做的库或组件?

谢谢

回答

您可以使用$graphLookup和其他有用的数组运算符,

  • $match记录只有的过滤器parent_idnull
  • $graphLookup 在depthField中获取子记录和深度数 level
  • $unwind解构children数组并允许不删除空子项
  • $sort按深度字段level降序排列
  • $groupid字段并重建children数组
db.collection.aggregate([
  { $match: { parent_id: null } },
  {
    $graphLookup: {
      from: "collection",
      startWith: "$id",
      connectFromField: "id",
      connectToField: "parent_id",
      depthField: "level",
      as: "children"
    }
  },
  {
    $unwind: {
      path: "$children",
      preserveNullAndEmptyArrays: true
    }
  },
  { $sort: { "children.level": -1 } },
  {
    $group: {
      _id: "$id",
      parent_id: { $first: "$parent_id" },
      name: { $first: "$name" },
      type: { $first: "$type" },
      category: { $first: 1 },
      children: { $push: "$children" }
    }
  },
  • $addFields 现在找到嵌套级别的孩子并分配给它的级别,
    • $reduce 迭代children数组循环。
    • 初始化默认字段level默认值为-1,presentChild为[],prevChild为条件目的为[]
    • $let 初始化字段:
      • prev根据条件如果两者level相等则返回prevChild否则返回presentChild
      • current根据条件,如果两者level相等则返回,presentChild否则返回[]
    • in从初始化字段返回level字段和prevChild字段
      • presentChild $filter childrenprev数组并返回,将当前对象与children数组 using合并,$mergeObjects并与currentlet 数组连接 using$concatArrays
  • $addFields只返回presentChild数组,因为我们只需要处理过的数组
  {
    $addFields: {
      children: {
        $reduce: {
          input: "$children",
          initialValue: { level: -1, presentChild: [], prevChild: [] },
          in: {
            $let: {
              vars: {
                prev: {
                  $cond: [
                    { $eq: ["$$value.level", "$$this.level"] },
                    "$$value.prevChild",
                    "$$value.presentChild"
                  ]
                },
                current: {
                  $cond: [{ $eq: ["$$value.level", "$$this.level"] }, "$$value.presentChild", []]
                }
              },
              in: {
                level: "$$this.level",
                prevChild: "$$prev",
                presentChild: {
                  $concatArrays: [
                    "$$current",
                    [
                      {
                        $mergeObjects: [
                          "$$this",
                          {
                            children: {
                              $filter: {
                                input: "$$prev",
                                as: "e",
                                cond: { $eq: ["$$e.parent_id", "$$this.id"] }
                              }
                            }
                          }
                        ]
                      }
                    ]
                  ]
                }
              }
            }
          }
        }
      }
    }
  },
  {
    $addFields: {
      id: "$_id",
      children: "$children.presentChild"
    }
  }
])

操场


以上是使用Express和Mongo使用递归表制作节点树的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>