聚合中扁平化MongoDB嵌套数组

时间:2018-09-04 11:05:22

标签: mongodb aggregation-framework

我有这样的文件:

{
    "many" : {},
    "other" : {},
    "fields" : {},
    "phases" : [ 
        {
            "type" : 10,
            "states" : [ 
                {
                    "type" : 10,
                    "time" : ISODate("2018-04-25T13:06:42.990+02:00")
                }, 
                {
                    "type" : 20,
                    "time" : ISODate("2018-04-25T13:26:12.122+02:00")
                }, 
                {
                    "type" : 30,
                    "time" : ISODate("2018-04-25T13:26:30.124+02:00")
                }
            ]
        }, 
        {
            "type" : 20,
            "states" : [ 
                {
                    "type" : 10,
                    "time" : ISODate("2018-04-25T13:27:58.201+02:00")
                }
            ]
        }
    ]
}

在聚合中,我试图将states包括父级的type展平,如下所示(期望的输出):

"states" : [ 
    {
        "phase": 10,
        "type" : 10,
        "time" : ISODate("2018-04-25T13:06:42.990+02:00")
    }, 
    {
        "phase": 10,
        "type" : 20,
        "time" : ISODate("2018-04-25T13:26:12.122+02:00")
    }, 
    {
        "phase": 10,
        "type" : 30,
        "time" : ISODate("2018-04-25T13:26:30.124+02:00")
    }, 
    {
        "phase": 20,
        "type" : 10,
        "time" : ISODate("2018-04-25T13:27:58.201+02:00")
    }
]

通过这种聚合,我已经完成了没有states字段的附加phase字段:

db.docs.aggregate([
{
    $addFields: {
        states: {
            $reduce: {
                  input: "$phases",
                  initialValue: [],
                  in: { $concatArrays: ["$$value", "$$this.states"] }
               }
           }
    }
}
])

“其他许多字段”应保留,因此我认为不能分组。
MongoDB版本是3.4。

我尝试了很多没有结果的事情。我想知道这是否可行以及如何实现。

4 个答案:

答案 0 :(得分:1)

db.state.aggregate(

// Pipeline
[
    // Stage 1
    {
        $unwind: {
            path : "$phases",
            includeArrayIndex : "arrayIndex", // optional
            preserveNullAndEmptyArrays : false // optional
        }
    },

    // Stage 2
    {
        $unwind: {
            path : "$phases.states",
            includeArrayIndex : "arrayIndex", // optional
            preserveNullAndEmptyArrays : false // optional
        }
    },

    // Stage 3
    {
        $project: {
            "phases":"$phases.type",
            "type":"$phases.states.type",
            "time":"$phases.states.time",
        }
    },

    // Stage 4
    {
        $group: {
            "_id":"$_id",
            states: { $push:  { phases: "$phases", type: "$type",time: "$time" } }
        }
    },
]);

答案 1 :(得分:1)

您需要使用$map遍历每个数组,然后可以使用$reduce$concat最终数组

db.collection.aggregate([
  { "$addFields": {
    "states": { "$reduce": {
      "input": { "$map": {
        "input": "$phases",
        "as": "pa",
        "in": { "$map": {
          "input": "$$pa.states",
          "as": "st",
          "in": { "type": "$$st.type", "time": "$$st.time", "phase": "$$pa.type" }
        }}
      }},
      "initialValue": [],
      "in": { "$concatArrays": ["$$value", "$$this"] }
    }}
  }}
])

答案 2 :(得分:0)

Mohit Kumar Bordia的代码看起来很棒。另外,如果您还想返回旧对象(基于Mohit代码):

db.getCollection('flatten').aggregate(

// Pipeline
[
    // Stage 1
    {
        $unwind: {
            path : "$phases",
            includeArrayIndex : "arrayIndex", // optional
            preserveNullAndEmptyArrays : false // optional
        }
    },

    // Stage 2
    {
        $unwind: {
            path : "$phases.states",
            includeArrayIndex : "arrayIndex", // optional
            preserveNullAndEmptyArrays : false // optional
        }
    },

    // Stage 3
    {
        $project: {
            "_id" : "$_id",
            "many" : "$many",
            "other" :"$other",
            "fields" : "$fields",
            "phases":"$phases.type",
            "type":"$phases.states.type",
            "time":"$phases.states.time",
        }
    },

    // Stage 4
    {
        $group: {
            "_id":"$_id",
            many : { $first: "$many"},
            other: { "$first": "$other" },
            fields: { "$first": "$fields" },
            states: { $push:  { phases: "$phases", type: "$type",time: "$time" } }
        }
    },
]);

答案 3 :(得分:0)

您可以使用以下汇总。使用$map来格式化状态数组,使其包含相位字段。

db.docs.aggregate([
  {"$addFields":{
    "states":{
      "$reduce":{
        "input":"$phases",
        "initialValue":[],
        "in":{
          "$concatArrays":[
            "$$value",
            {"$map":{
              "input":"$$this.states",
              "as":"state",
              "in":{"phase":"$$this.type","type":"$$state.type","time":"$$state.time"}
            }}
          ]
        }
      }
    }
  }}
])