使用 Express 和 Mongo 使用递归表制作节点树 [英] Make node tree with recursive table with Express and Mongo

查看:23
本文介绍了使用 Express 和 Mongo 使用递归表制作节点树的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

因此,如您所见,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":空,名称":帐户 1",类型":1,类别":1,儿童":[{id":45TYYXT",parent_id":45TYYU",名称":帐户 2",类型":1,类别":1,儿童":[{ "id": "45TYYPZGP", "parent_id": "45TYYXT", "name": "account 6", "type": 1, "category": 1 }]},{id":45TYYPZ",parent_id":45TYYU",名称":帐户 3",类型":1,类别":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":45TFJK",parent_id":空,名称":帐户 7",类型":1,类别":1,儿童":[{id":47HJJT",parent_id":45TFJK",名称":帐户 8",类型":1,类别":1},{id":47YHJU",parent_id":45TFJK",名称":帐户 8",类型":1,类别":1}]}]

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

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

谢谢

解决方案

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

  • $match 过滤器,记录只有 parent_idnull
  • $graphLookup 获取depthField level
  • 中的子记录和深度数
  • $unwind 解构 children 数组并允许不删除空子级
  • $sort 按深度级别字段 level 按降序排列
  • $group 通过 id 字段并重构 children 数组

db.collection.aggregate([{ $match: { parent_id: null } },{$graphLookup:{来自:收藏",startWith: "$id",connectFromField: "id",connectToField: "parent_id",深度字段:级别",如:儿童"}},{$展开:{路径:$children",preserveNullAndEmptyArrays: 真}},{ $sort: { "children.level": -1 } },{$组:{_id: "$id",parent_id: { $first: "$parent_id";},名称:{ $first:"$name"},类型:{ $first:$type";},类别:{ $first: 1 },孩子们:{ $push: "$children"}}},

  • $addFields 现在找到嵌套级别的子级并分配给它的级别,
    • $reduce 迭代 children 数组的循环.
    • 初始化默认字段 level 默认值为 -1,presentChild 为 [],prevChild 为 [] 用于条件目的
    • $let 初始化字段:
      • prev 根据条件如果两个 level 相等则返回 prevChild 否则返回 presentChild
      • current 根据条件如果两个 level 相等则返回 presentChild 否则返回 []
    • in 从初始化字段返回 level 字段和 prevChild 字段
      • presentChild $filter childrenprev数组返回,将当前对象与children<合并/code> 数组使用 $mergeObjects 并使用 $concatArrays
      • 与 let 的 current 数组连接
  • $addFields 只返回 presentChild 数组,因为我们只需要处理过的数组

<代码> {$addFields:{孩子们: {$减少:{输入:$儿童",initialValue: { level: -1, presentChild: [], prevChild: [] },在: {$let: {变量:{上一个:{$cond: [{ $eq: ["$$value.level", "$$this.level"] },$$value.prevChild",$$value.presentChild"]},当前的: {$cond: [{ $eq: ["$$value.level", "$$this.level"] }, "$$value.presentChild", []]}},在: {级别:$$this.level",prevChild: "$$prev",礼物孩子:{$concatArrays: [$$current",[{$合并对象:[$$this",{孩子们: {$过滤器:{输入:$$prev",如:e",cond: { $eq: ["$$e.parent_id", "$$this.id"] }}}}]}]]}}}}}}}},{$addFields:{id: "$_id",儿童:$children.presentChild"}}])

游乐场

I'm working in a REST api with ExpressJS and Mongo and I have a collection with N quantity of levels.

So to solve this problem I'm using an recursive table (or collection) in mongo where a field is the id and every register has a parent_id which is at the same level as it's childs. To explain better this, here is an E-R representation

So as you se, mongo will save the data like this json (accounts level 0 has null parent)

[
  { "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 }
]

account 2 and account 3 are children of account 1, while account 4 and account 5 are children of account tree and account 6 is child of account 2 ... but every register is at the same logical level only identifying through parent_id.

so I need to transform this data into a GET method to restructure it like this:

[
    { 
        "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
            }
        ]
    }
]

Yes... the parents level 0 has null parent_id and I want to put it's children inside an array called "children" and then send like this in the GET response to my UI

What is the best way to do this in expressJS? Is there a library or component out there that allows me to do this?

Thank you

解决方案

You can use $graphLookup and other useful array operators,

  • $match filter that records only have parent_id is null
  • $graphLookup to get child records and depth number in depthField level
  • $unwind deconstruct children array and allow to not remove empty children
  • $sort by depth level field level in descending order
  • $group by id field and reconstruct children array

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 now find the nested level children and allocate to its level,
    • $reduce to iterate loop of children array.
    • initialize default field level default value is -1, presentChild is [], prevChild is [] for the conditions purpose
    • $let to initialize fields:
      • prev as per condition if both level are equal then return prevChild otherwise return presentChild
      • current as per condition if both level are equal then return presentChild otherwise []
    • in to return level field and prevChild field from initialized fields
      • presentChild $filter children from prev array and return, merge current objects with children array using $mergeObjects and concat with current array of let using $concatArrays
  • $addFields to return only presentChild array because we only required that processed array

  {
    $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"
    }
  }
])

Playground

这篇关于使用 Express 和 Mongo 使用递归表制作节点树的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆