如何在MongoDB中选择两层模型的平面结构?

如何在MongoDB中选择两层模型的平面结构?,mongodb,aggregation-framework,Mongodb,Aggregation Framework,我在MongoDB中有一个两层结构模型,如下所示: export class ProductTypeModel { _id: ObjectID; name: string; children: { _id: ObjectID, name: string, icon: string }[]; } 它表示我的应用程序中的产品类型。实际上,子对象的属性与基本模型几乎相同,只是它有一个额外的图标属性 现在我有这样的数据:

我在MongoDB中有一个两层结构模型,如下所示:

export class ProductTypeModel {
    _id: ObjectID;
    name: string;
    children: {
        _id: ObjectID,
        name: string,
        icon: string
    }[];
}
它表示我的应用程序中的产品类型。实际上,
子对象
的属性与基本模型几乎相同,只是它有一个额外的
图标
属性

现在我有这样的数据:

{ 
    "_id" : ObjectId("5b9378d9a842a7557223ebfa"), 
    "name" : "Clothes", 
    "children" : [ { 
        "_id" : ObjectId("5b9378d9a842a7557223ebf6"), 
        "name" : "Men", 
        "icon": "xxx"
    }, { 
        "_id" : ObjectId("5b9378d9a842a7557223ebf7"), 
        "name" : "Women", 
        "icon": "xxx"
    }, { 
        "_id" : ObjectId("5b9378d9a842a7557223ebf8"), 
        "name" : "Shoes", 
        "icon": "xxx"
    }, { 
        "_id" : ObjectId("5b9378d9a842a7557223ebf9"), 
        "name" : "Underwear", 
        "icon": "xxx"
    } ] 
}
我希望它们被选为:

[
    { "_id" : ObjectId("5b9378d9a842a7557223ebfa"), "name" : "Clothes", "parent": null  },
    { "_id" : ObjectId("5b9378d9a842a7557223ebf6"), "name" : "Men", "icon": "xxx", "parent": ObjectId("5b9378d9a842a7557223ebfa") }, 
    { "_id" : ObjectId("5b9378d9a842a7557223ebf7"), "name" : "Women", "icon": "xxx", "parent": ObjectId("5b9378d9a842a7557223ebfa") }, 
    { "_id" : ObjectId("5b9378d9a842a7557223ebf8"), "name" : "Shoes", "icon": "xxx", "parent": ObjectId("5b9378d9a842a7557223ebfa") }, 
    { "_id" : ObjectId("5b9378d9a842a7557223ebf9"), "name" : "Underwear", "icon": "xxx", "parent": ObjectId("5b9378d9a842a7557223ebfa") }
]
在MongoDB中的一个查询中可以做到这一点吗


我尝试了
$unwind
,但结果中仍然包含两级结构。

您可以在下面的聚合中尝试

db.collection.aggregate([
  { "$project": {
    "data": {
      "$map": {
        "input": { "$concatArrays": ["$children", [{ "_id": "$_id", "name": "$name" }]] },
        "in": {
          "_id": "$$this._id",
          "icon": "$$this.icon",
          "name": "$$this.name",
          "parent": { "$cond": [{ "$eq": ["$$this.icon", undefined] }, null, "$_id"] }
        }
      }
    }
  }},
  { "$unwind": "$data" },
  { "$replaceRoot": { "newRoot": "$data" }}
])

这将实现以下目的:

父对象和子对象分别作为两个面处理。最后,将两个结果合并到一个数组中,然后无意将所有内容作为单独的文档提供

db.collection.aggregate(
{
    "$unwind": {
        "path": "$children"
    },
},
{
    "$facet": {
        "parentObjs": [
            {
                "$group": {
                    "_id": "$_id",
                    "name": { "$first": "$name" }
                }
            },
            {
                "$addFields": { 
                    "parent": null 
                }
            }
        ],
        "childObjs": [
            {
                "$project": {
                    "_id": "$children._id",
                    "name": "$children.name",
                    "icon": "$children.icon",
                    "parent": "$_id"
                }
            }
        ]
    }
},
{
    "$project": { "items": { "$concatArrays": [ "$parentObjs", "$childObjs" ] } }
},
{
    "$unwind": {
        "path": "$items"
    }
}
)

您需要做的就是:

db.collection.aggregate({
    $addFields: {
        "children.parent": "$_id" // push the "_id" field into every array element
    }
}, {
    $addFields: {
        "children": { $concatArrays: [ "$children", [ { "_id": "$_id", "name": "$name", "parent": null } ] ] } // a the parent item into the "children" array
    }
}, {
    $unwind: "$children" // flatten the array
}, {
    $replaceRoot: {
        "newRoot": "$children" // move all content inside the "children" field to the top
    }
})

对于顶层,父级需要为null。但我真的很喜欢地图的使用。我真正需要的是。。!将
$replaceRoot
项一起使用