2017-07-31 62 views
1

多个平均值我有收集象下面这样:在日期一定时期内如何从匹配的元素得到阵列

[{ 
    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

如果位置总是“固定”,那么你可以使用$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在模式为“都” a一个累加器和一个以“数组”作为参数本身的东西。因此“双”使用$avg

甚至使用$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' ] } 
      ] 
      } 
     } 
    }} 
]) 
+0

非常感谢。我可能知道为什么'$ timing.0.duration'在这里不支持? – ygjack

+0

@ygjack它从来没有过。虽然使用索引值的“点符号”形式对于“查询”和“投影”有效,但它对于聚合框架永远无效。只有从MongoDB 3.2开始,它实际上有效地得到一个“数组”,以响应诸如“$ timing.duration”之类的东西,并且在引入时'$ arrayElemAt'也被添加了。 –

+0

感谢您的解释 – ygjack