Mongodb $ graphLookup构建层次结构

时间:2019-01-05 00:49:16

标签: javascript mongodb mongoose graphlookup

我有mongodb $graphLookup聚合的输出:

db.getCollection('projects').aggregate([
    {
    $lookup: {
      from: "projects",
      localField: "_id",
      foreignField: "parent",
       as: "childrens"
     }
 }
])

{
    "_id" : "1",
    "name" : "Project1",
    "parent" : null,
    "childrens" : [ 
        {
            "_id" : "3",
            "name" : "ProjectForId1",
            "parent" : "1"
        }
    ]
},
{
    "_id" : "3",
    "name" : "ProjectForId1",
    "parent" : "1",
    "childrens" : [ 
        {
            "_id" : "6",
            "name" : "ProjectForId3",
            "parent" : "3"
        }, 
        {
            "_id" : "7",
            "name" : "ProjectForId3",
            "parent" : "3"
        }
    ]
}

我需要从javascript中的此输出构建层次结构,或者如果可能直接从查询中构建层次结构,则最终输出应类似于:

{
    "_id" : "1",
    "name" : "Project1",
    "parent" : null,
    "childrens" : [ 
        {
            "_id" : "3",
            "name" : "ProjectForId1",
            "parent" : "1",
            "childrens" : [ 
                {
                    "_id" : "6",
                    "name" : "ProjectForId3",
                    "parent" : "3"
                }, 
                {
                    "_id" : "7",
                    "name" : "ProjectForId3",
                    "parent" : "3"
                }
            ]
        }
    ]
} 

如果有人在其他情况下有勇敢的心可以提供帮助,则可以通过过滤_id来创建层次结构:

ex:对于_id = "1",输出将与上面相同,但是如果_id3,则最终输出应类似于:

{
    "_id" : "3",
    "name" : "ProjectForId1",
    "parent" : "1",
    "childrens" : [ 
        {
            "_id" : "6",
            "name" : "ProjectForId3",
            "parent" : "3"
        }, 
        {
            "_id" : "7",
            "name" : "ProjectForId3",
            "parent" : "3"
        }
    ]
}

1 个答案:

答案 0 :(得分:1)

以下解决方案与我过去的答案大致相同,因此您可以得到详尽的解释here

db.projects.aggregate([
    {
        $graphLookup: {
            from: "projects",
            startWith: "$_id",
            connectFromField: "_id",
            connectToField: "parent",
            as: "children",
            maxDepth: 4,
            depthField: "level"
        }
    },
    {
        $unwind: "$children"
    },
    {
        $sort: { "children.level": -1 }
    },
    {
        $group: {
            _id: "$_id",
            children: { $push: "$children" }
        }
    },
    {
        $addFields: {
            children: {
                $reduce: {
                    input: "$children",
                    initialValue: {
                        currentLevel: -1,
                        currentLevelProjects: [],
                        previousLevelProjects: []
                    },
                    in: {
                        $let: {
                            vars: {
                                prev: { 
                                    $cond: [ 
                                        { $eq: [ "$$value.currentLevel", "$$this.level" ] }, 
                                        "$$value.previousLevelProjects", 
                                        "$$value.currentLevelProjects" 
                                    ] 
                                },
                                current: { 
                                    $cond: [ 
                                        { $eq: [ "$$value.currentLevel", "$$this.level" ] }, 
                                        "$$value.currentLevelProjects", 
                                        [] 
                                    ] 
                                }
                            },
                            in: {
                                currentLevel: "$$this.level",
                                previousLevelProjects: "$$prev",
                                currentLevelProjects: {
                                    $concatArrays: [
                                        "$$current", 
                                        [
                                            { $mergeObjects: [ 
                                                "$$this", 
                                                { children: { $filter: { input: "$$prev", as: "e", cond: { $eq: [ "$$e.parent", "$$this._id"  ] } } } } 
                                            ] }
                                        ]
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    {
        $addFields: { children: "$children.currentLevelProjects" }
    },
    {
        $match: {
            _id: "1"
        }
    }
])

上一个阶段应该是过滤,因此您可以在此处获取任何深度级别的数据。