MongoDB $graphLookup 获取所有级别的子项 - 嵌套结果
MongoDB $graphLookup get children all levels deep - nested result
如 https://www.slideshare.net/mongodb/webinar-working-with-graph-data-in-mongodb、幻灯片 50 中所述,可以在视图上使用 $graphLookup
以获得 2 层深的树结构嵌套格式.
我有一个 MongoDB 集合,其中树节点作为文档,格式如下:
{ "_id" : { "$oid" : "5b1a952361c6fa3418a15660" },
"nodeId" : 23978995,
"name" : "settings",
"type" : "Node",
"parentId" : [ 23978893, 23979072, 23979081 ] }
我创建了一个像这样的视图:
db.createView("treeView", "node", [
{
$graphLookup: {
from: "node",
startWith: "$nodeId",
connectFromField: "nodeId",
connectToField: "parentId",
maxDepth: 0,
as: "children"
}
}
]);
然后我执行图形查找,例如:
db.node.aggregate([
{ $match: {"nodeId": 23978786 } },
{
$graphLookup: {
from: "treeView",
startWith: "$nodeId",
connectFromField: "nodeId",
connectToField: "parentId",
maxDepth: 0,
as: "children"
}
}
]);
我的问题是如何获得整个层次结构,所有级别的深度?
遗憾的是,您无法获得嵌套格式的完整深度。使用视图是一种解决方法,可让您执行该操作,但您需要为所需的每个嵌入级别创建一个新视图。
相反,我会考虑在不提供深度的情况下执行 graphLookup,从根级别开始,在单个查询中获取所有层次结构,然后在应用程序级别计算树。
这看起来像这样:
db.node.aggregate([
{ $match: {
parentId: null
}},
{ $graphLookup: {
from: "node",
startWith: "$nodeId",
connectFromField: "nodeId",
connectToField: "parentId",
depthField: "depth",
as: "children"
}}
]);
这应该可以让您一次性获取整个层次结构,因此接下来,您需要根据 "children" 数组中的信息计算应用程序中的树。
@kmandalas 我最近两天遇到了这种问题,
我的 collection 有点不同,但概念与你的相同我希望我写的内容能帮助你得到结果,(我使用 SO 答案的参考)
我的 Collection 架构如下:
const Category = new Schema({
sTitle: { type: String, trim: true },
iParentId: { type: mongoose.Schema.Types.ObjectId, ref: 'Category' },
bStatus: { type: Boolean, default: true },
dUpdatedAt: { type: Date },
dCreatedAt: { type: Date, default: Date.now }
});
首先,我使用 $graphLookup,然后我将所有 children 归为一个合适的 parent,例如:
{
"_id": "5c6fa228c30bbf02cf12fe6c",
"sTitle": "firstParent",
"childrens":[{obj},{obj},{obj},{obj}] // Childrens as well as grandChild
},
{
"_id": "5c80d644ab57dd06d48cc474",
"sTitle": "secondParent",
"childrens":[] //No Child
},
.....
得到这种结果后,我在节点 js 中创建了一棵树,没有使用任何 third-party 库。
树逻辑代码是:(!note:docs is $graphlooup output nothing else)
function list_to_tree(list) {
var map = {}, node, roots = [], i;
for (i = 0; i < list.length; i += 1) {
map[list[i]._id] = i;
list[i].children = [];
}
for (i = 0; i < list.length; i += 1) {
node = list[i];
if (node.iParentId !== null && map[node.iParentId] !== undefined) {
var node2 = { //Because i need only _id,Title & childrens
_id: node._id,
Title: node.sTitle,
children: node.children
}
list[map[node.iParentId]].children.push(node2); //You can push direct "node"
} else {
var node2 = {
_id: node._id,
Title: node.sTitle,
children: node.children
}
roots.push(node2);
}
}
return roots;
}
let final_result = [] //For Storing all parent with childs
if (docs.length >= 0) {
docs.map(single_doc => { //For getting all parent Tree
var single_child = list_to_tree(single_doc.children)
var obj = {
_id: single_doc._id,
Title: single_doc.sTitle,
children: single_child
}
final_result.push(obj)
})
}
console.log("Final Tree is : ",final_result)
希望对您有所帮助
如 https://www.slideshare.net/mongodb/webinar-working-with-graph-data-in-mongodb、幻灯片 50 中所述,可以在视图上使用 $graphLookup
以获得 2 层深的树结构嵌套格式.
我有一个 MongoDB 集合,其中树节点作为文档,格式如下:
{ "_id" : { "$oid" : "5b1a952361c6fa3418a15660" },
"nodeId" : 23978995,
"name" : "settings",
"type" : "Node",
"parentId" : [ 23978893, 23979072, 23979081 ] }
我创建了一个像这样的视图:
db.createView("treeView", "node", [
{
$graphLookup: {
from: "node",
startWith: "$nodeId",
connectFromField: "nodeId",
connectToField: "parentId",
maxDepth: 0,
as: "children"
}
}
]);
然后我执行图形查找,例如:
db.node.aggregate([
{ $match: {"nodeId": 23978786 } },
{
$graphLookup: {
from: "treeView",
startWith: "$nodeId",
connectFromField: "nodeId",
connectToField: "parentId",
maxDepth: 0,
as: "children"
}
}
]);
我的问题是如何获得整个层次结构,所有级别的深度?
遗憾的是,您无法获得嵌套格式的完整深度。使用视图是一种解决方法,可让您执行该操作,但您需要为所需的每个嵌入级别创建一个新视图。 相反,我会考虑在不提供深度的情况下执行 graphLookup,从根级别开始,在单个查询中获取所有层次结构,然后在应用程序级别计算树。
这看起来像这样:
db.node.aggregate([
{ $match: {
parentId: null
}},
{ $graphLookup: {
from: "node",
startWith: "$nodeId",
connectFromField: "nodeId",
connectToField: "parentId",
depthField: "depth",
as: "children"
}}
]);
这应该可以让您一次性获取整个层次结构,因此接下来,您需要根据 "children" 数组中的信息计算应用程序中的树。
@kmandalas 我最近两天遇到了这种问题, 我的 collection 有点不同,但概念与你的相同我希望我写的内容能帮助你得到结果,(我使用 SO 答案的参考)
我的 Collection 架构如下:
const Category = new Schema({
sTitle: { type: String, trim: true },
iParentId: { type: mongoose.Schema.Types.ObjectId, ref: 'Category' },
bStatus: { type: Boolean, default: true },
dUpdatedAt: { type: Date },
dCreatedAt: { type: Date, default: Date.now }
});
首先,我使用 $graphLookup,然后我将所有 children 归为一个合适的 parent,例如:
{
"_id": "5c6fa228c30bbf02cf12fe6c",
"sTitle": "firstParent",
"childrens":[{obj},{obj},{obj},{obj}] // Childrens as well as grandChild
},
{
"_id": "5c80d644ab57dd06d48cc474",
"sTitle": "secondParent",
"childrens":[] //No Child
},
.....
得到这种结果后,我在节点 js 中创建了一棵树,没有使用任何 third-party 库。 树逻辑代码是:(!note:docs is $graphlooup output nothing else)
function list_to_tree(list) {
var map = {}, node, roots = [], i;
for (i = 0; i < list.length; i += 1) {
map[list[i]._id] = i;
list[i].children = [];
}
for (i = 0; i < list.length; i += 1) {
node = list[i];
if (node.iParentId !== null && map[node.iParentId] !== undefined) {
var node2 = { //Because i need only _id,Title & childrens
_id: node._id,
Title: node.sTitle,
children: node.children
}
list[map[node.iParentId]].children.push(node2); //You can push direct "node"
} else {
var node2 = {
_id: node._id,
Title: node.sTitle,
children: node.children
}
roots.push(node2);
}
}
return roots;
}
let final_result = [] //For Storing all parent with childs
if (docs.length >= 0) {
docs.map(single_doc => { //For getting all parent Tree
var single_child = list_to_tree(single_doc.children)
var obj = {
_id: single_doc._id,
Title: single_doc.sTitle,
children: single_child
}
final_result.push(obj)
})
}
console.log("Final Tree is : ",final_result)
希望对您有所帮助