2017-07-31 38 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 }] 
}] 

を、私は日付の指定期間中に指定したページの平均タイミングの結果が欲しいです。例えば

:私は日20170701から、ページ1の平均タイミングデータを必要とする - 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「両方」 nアキュムレータと、引数自体として「配列」をとるものです。したがっては "double"の使用$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

explainationのおかげで – ygjack

関連する問題