我想查询mongodb中整个树形结构,我找到了一段代码这里。
聚合外壳。
[
{
$match: { pid: 0 }
},
{
$graphLookup: {
from: "administrative_divisions",
startWith: "$_id",
connectFromField: "_id",
connectToField: "pid",
depthField: "level",
as: "children"
}
},
{
$unwind: {
path: "$children",
preserveNullAndEmptyArrays: true
}
},
{
$sort: {
"children.level": -1
}
},
{
$group: {
_id: "$_id",
name: {
$first: "$name"
},
path: {
$first: "$path"
},
pid: {
$first: "$pid"
},
children: {
$push: "$children"
}
}
},
{
$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.pid",
"$$this._id"
]
}
}
}
}
]
}
]
]
}
}
}
}
}
}
}
},
{
$addFields: {
children: "$children.presentChild"
}
}
]
但是这段代码中并没有根据字段进行排序。
如果每个节点有一个字段
sort
,Java类型是BigDecimal
,mongoDB类型是string
。
使用的数据例如:
[
{
"_id": 1,
"name": "New York State",
"pid": 0,
"level": 1,
"sort": 2.00223000,
"leaf": false,
"path": "1"
},
{
"_id": 2,
"name": "New York City",
"pid": 1,
"level": 2,
"sort": 2.0000000,
"leaf": false,
"path": "1, 2"
},
{
"_id": 4,
"name": "The Bronx",
"pid": 2,
"level": 3,
"sort": 1.0000000,
"leaf": true,
"path": "1, 2, 4"
},
{
"_id": 5,
"name": "Brooklyn",
"pid": 2,
"level": 3,
"sort": 4.0000000,
"leaf": true,
"path": "1, 2, 5"
},
{
"_id": 6,
"name": "Manhattan",
"pid": 2,
"level": 3,
"sort": 5.0000000,
"leaf": true,
"path": "1, 2, 6"
},
{
"_id": 7,
"name": "Queens",
"pid": 2,
"level": 3,
"sort": 6.0000000,
"leaf": true,
"path": "1, 2, 7"
},
{
"_id": 8,
"name": "Staten Island",
"pid": 2,
"level": 3,
"sort": 12.0002220,
"leaf": true,
"path": "1, 2, 8"
},
{
"_id": 3,
"name": "Albany",
"pid": 1,
"level": 2,
"sort": 1.0023400,
"leaf": true,
"path": "1, 3"
}
]
同级别的节点按照排序号升序排列。
我期待最终的结果:
{
"_id": 1,
"name": "New York State",
"path": "1",
"pid": 0,
"children": [
{
"_id": 3,
"name": "Albany",
"pid": 1,
"level": {
"$numberLong": "0"
},
"sort": 1.00234,
"leaf": true,
"path": "1, 3",
"children": []
},
{
"_id": 2,
"name": "New York City",
"pid": 1,
"level": {
"$numberLong": "0"
},
"sort": 2,
"leaf": false,
"path": "1, 2",
"children": [
{
"_id": 4,
"name": "The Bronx",
"pid": 2,
"level": {
"$numberLong": "1"
},
"sort": 1,
"leaf": true,
"path": "1, 2, 4",
"children": []
},
{
"_id": 5,
"name": "Brooklyn",
"pid": 2,
"level": {
"$numberLong": "1"
},
"sort": 4,
"leaf": true,
"path": "1, 2, 5",
"children": []
},
{
"_id": 6,
"name": "Manhattan",
"pid": 2,
"level": {
"$numberLong": "1"
},
"sort": 5,
"leaf": true,
"path": "1, 2, 6",
"children": []
},
{
"_id": 7,
"name": "Queens",
"pid": 2,
"level": {
"$numberLong": "1"
},
"sort": 6,
"leaf": true,
"path": "1, 2, 7",
"children": []
},
{
"_id": 8,
"name": "Staten Island",
"pid": 2,
"level": {
"$numberLong": "1"
},
"sort": 12.000222,
"leaf": true,
"path": "1, 2, 8",
"children": []
}
]
}
]
}
如何让查询结果根据
sort
字段进行排序?
仅供参考,不一定正确,因为数据有改动。
我尝试用
替换{ $sort: { "children.level": -1 } }
,这破坏了最终结果。{ $sort: { "children.sort": 1 } }
将
或{ $sort: { "children.sort": 1 } }
添加到最终管道也不起作用。{ $sort: { "sort": 1 } }
我认为你只需要在
children.sort: 1
阶段的 children.level
之后在 $sort
添加 1 级排序即可。
db.administrative_divisions.aggregate([
{
"$match": {
pid: 0
}
},
{
$graphLookup: {
from: "administrative_divisions",
startWith: "$_id",
connectFromField: "_id",
connectToField: "pid",
depthField: "level",
as: "children"
}
},
{
$unwind: {
path: "$children",
preserveNullAndEmptyArrays: true
}
},
{
$sort: {
"children.level": -1,
"children.sort": 1
}
},
{
$group: {
_id: "$_id",
name: {
$first: "$name"
},
path: {
$first: "$path"
},
pid: {
$first: "$pid"
},
children: {
$push: "$children"
}
}
},
{
$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.pid",
"$$this._id"
]
}
}
}
}
]
}
]
]
}
}
}
}
}
}
}
},
{
$addFields: {
children: "$children.presentChild"
}
}
])