如何在MongoDB中选择二级模型的平面结构?

时间:2018-09-20 15:25:12

标签: mongodb aggregation-framework

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

export class ProductTypeModel {
    _id: ObjectID;
    name: string;
    children: {
        _id: ObjectID,
        name: string,
        icon: string
    }[];
}

它代表我的应用程序中的产品类型。实际上,children具有与基本模型几乎相同的属性,只是它具有额外的icon属性。

现在我有这样的数据:

{ 
    "_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,但结果中仍然包含两个级别的结构。

3 个答案:

答案 0 :(得分:2)

您可以尝试以下汇总

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

答案 1 :(得分:0)

这可以解决问题:

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

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

答案 2 :(得分:0)

您需要做的就是这个

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