使用 Express 和 Mongo 制作带有递归表的节点树
Posted
技术标签:
【中文标题】使用 Express 和 Mongo 制作带有递归表的节点树【英文标题】:Make node tree with recursive table with Express and Mongo 【发布时间】:2021-03-16 05:50:03 【问题描述】:我正在使用 ExpressJS 和 Mongo 使用 REST api,并且我有一个包含 N 个级别的集合。
所以为了解决这个问题,我在 mongo 中使用了一个递归表(或集合),其中一个字段是 id,每个寄存器都有一个 parent_id,它与它的子级处于同一级别。 为了更好地解释这一点,这里是一个 E-R 表示
如你所见,mongo 会像这样保存 json 数据(帐户级别 0 的父级为空)
[
"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 中最好的方法是什么? 是否有允许我这样做的库或组件?
谢谢
【问题讨论】:
【参考方案1】:您可以使用$graphLookup 和其他有用的数组运算符,
记录只有parent_id
的$match
过滤器是null
$graphLookup
获取depthField中的子记录和深度号level
$unwind
解构 children
数组并允许不移除空子节点
$sort
按深度级别字段 level
降序排列
$group
by id
字段并重构 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
children
来自prev
数组并返回,使用$mergeObjects
将当前对象与children
数组合并,并使用$concatArrays
与current
数组合并
$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"
])
Playground
【讨论】:
以上是关于使用 Express 和 Mongo 制作带有递归表的节点树的主要内容,如果未能解决你的问题,请参考以下文章
通过 express、mongoose 和 angular 删除 mongo 文档时出现 404
CVE-2019-10758-Mongo-express-远程代码执行
你能告诉我 express-mongo-sanitize 是不是有效吗?