使用 Express 和 Mongo 使用递归表制作节点树 [英] Make node tree with recursive table with Express and 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_id
是null
$graphLookup
获取depthFieldlevel
中的子记录和深度数$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
children
从prev
数组返回,将当前对象与children<合并/code> 数组使用
$mergeObjects
并使用$concatArrays
与 let 的
current
数组连接
- $reduce 迭代
$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 haveparent_id
isnull
$graphLookup
to get child records and depth number in depthFieldlevel
$unwind
deconstructchildren
array and allow to not remove empty children$sort
by depth level fieldlevel
in descending order$group
byid
field and reconstructchildren
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 bothlevel
are equal then returnprevChild
otherwise returnpresentChild
current
as per condition if bothlevel
are equal then returnpresentChild
otherwise []
in
to returnlevel
field andprevChild
field from initialized fieldspresentChild
$filter
children
fromprev
array and return, merge current objects withchildren
array using$mergeObjects
and concat withcurrent
array of let using$concatArrays
- $reduce to iterate loop of
$addFields
to return onlypresentChild
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"
}
}
])
这篇关于使用 Express 和 Mongo 使用递归表制作节点树的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!