如何在 mongodb 中查询树结构并对子级进行排序

问题描述 投票:0回答:1

我想查询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 } }
添加到最终管道也不起作用。

mongodb
1个回答
0
投票

我认为你只需要在

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

蒙戈游乐场

© www.soinside.com 2019 - 2024. All rights reserved.