【问题标题】:Aggregate to get average from document and of array elements聚合以从文档和数组元素中获取平均值
【发布时间】:2017-06-30 16:14:59
【问题描述】:

我有这些对象的数组:

item1 = {
  name:'item',
  val:1,
  list:[
    {type:'a',value:1},
    {type:'b',value:1},
    {type:'c',value:1}
  ]
};

item2 = {
  name:'item',
  val:5,
  list:[
    {type:'a',value:3},
    {type:'b',value:99},
    {type:'c',value:1}
  ]
};

它们都有相同的数组,相同的类型“a”、“b”和“c”,但值不同。

如何获取类型“a”、“b”和“c”的平均值?

我怎样才能得到所有项目的平均值?

我期待

itemAvg = {
  name:'item',
  val:3,
  list:[
    {type:'a',value:2},
    {type:'b',value:50},
    {type:'c',value:1}
  ]
};

我认为首先按名称对 val 进行分组并推送列表。 然后展开列表。 然后按类型对列表进行分组。

但这不起作用

model.aggregate([
{ $match : <condition> },
{ $group : {
  _id:{name:'$name'},
  ValAvg:{$avg:'$val'}
  List:{$push:'list'}
}},
{ $unwind:'$List'},
{ $group:{                
  _id:{type:'$List.type',
  ValueAvg:{$avg:'$List.value'}
}}
])

我希望展开后的最后一组会按曲调类型分组并计算每种不同类型的平均值......但没有......我得到 ValueAvg=0

谢谢

【问题讨论】:

    标签: node.js mongodb mongoose mongodb-query aggregation-framework


    【解决方案1】:

    您需要两个 $unwind 阶段,因为您将数组推送到一个数组中,然后跟进两个 $group 阶段:

    model.aggregate([
        { "$match": { <condition> }},
        { "$group": {
            "_id": "name",
            "val": { "$avg": "$val" },
            "list": { "$push": "$list" }
        }},
        { "$unwind": "$list" },
        { "$unwind": "$list" },
        { "$group": {
            "_id": { "name": "$_id", "type": "$list.type" },
            "val": { "$avg": "$val" },
            "valAvg": { "$avg": "$list.value" }
        }},
        { "$sort": { "_id": 1 } },
        { "$group": {
            "_id": "$_id.name",
            "val": { "$avg": "$val" },
            "list": { "$push": {
               "type": "$_id.type",
               "value": "$valAvg"
            }}
        }}
    ])
    

    因此,通过首先在“类型”级别进行分组,获得的结果可以获得元素之间的平均值,然后重建原始形式。注意$sort要保留元素的顺序,否则会颠倒:

    {
        "_id" : "name",
        "val" : 3,
        "list" : [
                {
                        "type" : "a",
                        "value" : 2
                },
                {
                        "type" : "b",
                        "value" : 50
                },
                {
                        "type" : "c",
                        "value" : 1
                }
        ]
    }
    

    如果您想先$unwind 以避免将数组放入数组中,请不要这样做。您在数组外寻找的平均值将受到展开时数组中元素数量的影响。因此,在一个文档中具有更多元素的数组相对于另一个文档在确定那里的平均值时会“加权”它们的值。

    【讨论】:

    • 非常感谢,完全正确。我仍然不是 100% 确定这是如何工作的,但感谢您的解决方案,我会更仔细地研究它
    • @user1144446 花更多时间研究.aggregate() 并阅读所有文档。对我来说最好的(仍然)是执行管道,同时添加“一次一个阶段”并检查每个阶段的结果。这是可视化正在发生的事情的最佳方式,也是学习的最佳方式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-29
    相关资源
    最近更新 更多