如何使用mongoDB基于元素属性从一个元素中的数组元素中收集数据

时间:2018-04-13 17:26:09

标签: mongodb aggregation-framework aggregate

看起来非常简单,任何语言都是4-5行。我真的被卡住了! 我已经拥有的东西:

/* 1 */
{
    "_id" : ObjectId("5ad078cc43c90bb8118b457b"),
    "totalTime" : 323,
    "qData" : [ 
        {
            "qId" : "123456",
            "weight" : 38
        }, 
        {
            "qId" : "654321",
            "age" : 21
        },       
        {
            "qId" : "123456",
            "age" : 14
        }, 
        {
            "qId" : "654321",
            "height" : 122
        }, 
        {
            "qId" : "654321",
            "weight" : 34
        }
    ]
}

/* 2 */
{
    "_id" : ObjectId("5ad084cc43c90bb8118b4583"),
    "totalTime" : 312,
     "qData" : [ 
        {
            "qId" : "123456",
            "weight" : 42
        }, 
        {
            "qId" : "654321",
            "age" : 21
        },       
        {
            "qId" : "123456",
            "age" : 15
        }, 
        {
            "qId" : "654321",
            "height" : 124
        }, 
        {
            "qId" : "654321",
            "weight" : 40
        }
    ]
}

/* 3 */
{
    "_id" : ObjectId("5ad0853143c90bf4088b457b"),
    "totalTime" : NumberLong(20),
     "qData" : [ 
        {
            "qId" : "123456",
            "weight" : 48
        }, 
        {
            "qId" : "654321",
            "age" : 22
        },       
        {
            "qId" : "123456",
            "age" : 19
        }, 
        {
            "qId" : "654321",
            "height" : 162
        }, 
        {
            "qId" : "654321",
            "weight" : 39
        }
    ]
}

我需要去的地方。这只是根据每个元素的qDatadocument数组中为每个qId收集数据。文档(记录)根本不会混合他们的数据(qData)。

/* 1 */
{
    "_id" : ObjectId("5ad078cc43c90bb8118b457b"),
    "totalTime" : 323,
    "qData" : [ 
        {
            "qId" : "123456",
            "weight" : 38,
            "age" : 14
        }, 
        {
            "qId" : "654321",
            "age" : 21,
            "height" : 122,
            "weight" : 34
        }
    ]
}

/* 2 */
{
    "_id" : ObjectId("5ad084cc43c90bb8118b4583"),
    "totalTime" : 312,
     "qData" : [ 
        {
            "qId" : "123456",
            "weight" : 42,
            "age" : 15
        }, 
        {
            "qId" : "654321",
            "age" : 21,
            "height" : 124,
            "weight" : 40
        }
    ]
}

/* 3 */
{
    "_id" : ObjectId("5ad0853143c90bf4088b457b"),
    "totalTime" : NumberLong(20),
     "qData" : [ 
        {
            "qId" : "123456",
            "weight" : 48,
            "age" : 19
        }, 
        {
            "qId" : "654321",
            "age" : 22,
            "height" : 162,
            "weight" : 39
        }
    ]
}

我需要使用聚合框架来做这件事。已经尝试使用$ map或$ addToSet的$ filter已经花费了10个小时。找不到合适的组合。

更新:我忘了提及,我在3.4上运行,所以$mergeObjects不是没有更新的选项。

2 个答案:

答案 0 :(得分:1)

您可以在3.6中尝试以下聚合。

db.collection.aggregate([
  {"$unwind":"$qData"},
  {"$group":{
    "_id":{"id":"$_id","qId":"$qData.qId"},
    "totalTime":{"$first":"$totalTime"},
    "mergedata":{"$mergeObjects":"$qData"}
  }},
  {"$group":{
    "_id":"$_id.id",
    "totalTime":{"$first":"$totalTime"},
    "qData":{"$push":"$mergedata"}
  }}
])

对于3.4,您可以使用以下查询。

db.collection.aggregate([
  {"$unwind":"$qData"},
  {"$group":{
    "_id":{"id":"$_id","qId":"$qData.qId"},
    "totalTime":{"$first":"$totalTime"},
    "arraydata":{"$push": {"$objectToArray":"$qData"}}
  }},
  {"$addFields":{"arraydata":{"$arrayToObject":{
     "$reduce":{
       "input":"$arraydata",
       "initialValue":[],
       "in":{"$concatArrays":["$$this","$$value"]}}
   }}}},
   {"$group":{
    "_id":"$_id.id",
    "totalTime":{"$first":"$totalTime"},
    "qData":{"$push": "$arraydata"}
  }}
])

答案 1 :(得分:0)

从@ Veeram的答案中获得最大好处的一件小事。走向Veeram的方式也会产生一些噪音:

        {
            "qId" : "123456",
            "qId" : "123456",
            "weight" : 48,
            "age" : 19
        }

所以我修复它的方法是在减少数组的同时添加$setUnion

 $reduce : {
           input:"$arraydata",
           initialValue:[],
           in:{ $setUnion : {$concatArrays:["$$this","$$value"]}}
 }