如何从数组中的匹配元素中获取多个平均值

时间:2017-07-31 06:01:10

标签: mongodb mongodb-query aggregation-framework

我的收藏如下:

[{
    date: '20170721',
    pageUrl: 'page1',
    timing: [{ name: 'dns', duration: 1000 }, { name: 'tcp', duration: 2000 }]
}, {
    date: '20170721',
    pageUrl: 'page2',
    timing: [{ name: 'dns', duration: 1001 }, { name: 'tcp', duration: 1800 }]
}, {
    date: '20170722',
    pageUrl: 'page1',
    timing: [{ name: 'dns', duration: 1021 }, { name: 'tcp', duration: 1700 }]
}, {
    date: '20170722',
    pageUrl: 'page2',
    timing: [{ name: 'dns', duration: 1101 }, { name: 'tcp', duration: 1850 }]
}]

我希望在给定的一段时间内给定页面的平均时间结果。

例如:我需要第1页的平均时间数据,从20170701 - 20170731开始

预期的输出应该是:

[{
    _id: '20170701',
    dns: <avgDuration>,
    tcp: <avgDuration>
}, {
    _id: '20170702',
    dns: <avgDuration>,
    tcp: <avgDuration>
},
...
]

我尝试过的是,它不起作用:

db.myCollection.aggregate([
    { $match: { 'pageUrl': targetPageUrl } },
    { $group: {
        _id: '$date',
        dns: { $avg: '$timing.0.duration' },
        tcp: { $avg: '$timing.1.duration' }
    },
    ...
])

有人可以帮忙吗?请

1 个答案:

答案 0 :(得分:1)

如果这些职位总是“固定”,那么您可以使用$arrayElemAt

db.myCollection.aggregate([
    { '$match': { 'pageUrl': targetPageUrl } },
    { '$group': {
        _id: '$date',
        dns: { '$avg': { '$arrayElemAt': [ '$timing.duration', 0 ] }  },
        tcp: { '$avg': { '$arrayElemAt': [ '$timing.duration', 1 ] } }
    }}
])

如果它们实际上没有修复,请使用$filter获取匹配值:

db.myCollection.aggregate([
    { '$match': { 'pageUrl': targetPageUrl } },
    { '$group': {
        _id: '$date',
        dns: { 
          '$avg': {
            '$avg': {
              '$map': {
                'input': { 
                 '$filter': {
                   'input': '$timing',
                   'as': 't',
                   'cond': { '$eq': [ '$$t.name', 'dns' ] }
                 },
                 'as': 't',
                 'in': '$$t.duration'
               } 
            }
          }
        },
        tcp: { 
          '$avg': { 
            '$avg': {
              '$map': {
                'input': { 
                 '$filter': {
                   'input': '$timing',
                   'as': 't',
                   'cond': { '$eq': [ '$$t.name', 'tcp' ] }
                 },
                 'as': 't',
                 'in': '$$t.duration'
               }
            }
          }
        }
    }}
])

$filter一样,实际上可以在数组中使用“多个匹配”,并在模式中使用$avg“减少”它们“both”一个累加器和一个以“数组”作为参数本身的东西。因此$avg“double”用法。

如果您认为自己真的必须,甚至可以使用$indexOfArray

db.myCollection.aggregate([
    { '$match': { 'pageUrl': targetPageUrl } },
    { '$group': {
        _id: '$date',
        dns: { 
          '$avg': {
            '$arrayElemAt': [
              '$timing.duration',
              { '$indexOfArray': [ '$timing.name', 'dns' ] }
            ]
          }
        },
        tcp: { 
          '$avg': {
            '$arrayElemAt': [
              '$timing.duration',
              { '$indexOfArray': [ '$timing.name', 'tcp' ] }
            ]
          }
        }
    }}
])