2015-05-06 59 views
2

我有以下收集結構mongodb的平均

{ 
    "_id": { 
    "d_timestamp": NumberLong(1429949699), 
    "d_isostamp": ISODate("2015-04-25T08:14:59.0Z") 
    }, 
    "XBT-USD-cpx-okc": [ 
    { 
     "buySpread": -1.80081 
    } 

我運行以下聚合

$spreadName ='XBT-USD-stp-nex'; 
$pipe = array(
    array(
     '$match' => array(
      '_id.d_isostamp' => array(
       '$gt' => $start, '$lt' => $end 
      ) 
     ) 
    ), 
    array(
     '$project' => array(
      'sellSpread' =>'$'.$spreadName.'.sellSpread', 
     ) 
    ), 
    array(
     '$group' => array(
      '_id' => array(
       'isodate' => array(
        '$minute' => '$_id.d_isostamp' 
       ) 
      ), 
      'rsell_spread' => array(
       '$avg' => '$sellSpread' 
      ), 
     ) 
    ), 
); 

$out = $collection->aggregate($pipe ,$options); 

,我得到作爲結果的值0爲rsell_spread而如果我跑例如$max而不是$group中的$avg,我得到準確的值rsell_spread,具有以下結構

{ 
    "_id": { 
    "isodate": ISODate("2015-04-25T08:00:58.0Z") 
    }, 
    "rsell_spread": [ 
    -4.49996▼ 
    ] 
} 

所以我有兩個問題:

1 /怎麼會沒有了$avg功能不起作用?

2 /當我使用$max例如(只是一個常規數字)時,我怎麼能不能在一個數組中?

回答

1
  1. $avg組累加器操作者不工作,這是隻在你的情況下,它被施加到陣列中的一個元件,從而給出了「不正確」的結果。

  2. 當您使用$max組累加器運算符時,它將返回將表達式應用於一組文檔中的每個文檔所產生的最高值,因此在您的示例中它將返回最大數組。

爲了證明這一點,考慮mongoshell添加一些樣本文檔的測試集:

db.test.insert([ 
{ 
    "_id" : { 
     "d_timestamp" : NumberLong(1429949699), 
     "d_isostamp" : ISODate("2015-04-25T08:14:59.000Z") 
    }, 
    "XBT-USD-stp-nex" : [ 
     { 
      "sellSpread" : -1.80081 
     } 
    ] 
}, 
{ 
    "_id" : { 
     "d_timestamp" : NumberLong(1429949710), 
     "d_isostamp" : ISODate("2015-04-25T08:15:10.000Z") 
    }, 
    "XBT-USD-stp-nex" : [ 
     { 
      "sellSpread" : -1.80079 
     } 
    ] 
}, 
{ 
    "_id" : { 
     "d_timestamp" : NumberLong(1429949720), 
     "d_isostamp" : ISODate("2015-04-25T08:15:20.000Z") 
    }, 
    "XBT-USD-stp-nex" : [ 
     { 
      "sellSpread" : -1.80083 
     } 
    ] 
}, 
{ 
    "_id" : { 
     "d_timestamp" : NumberLong(1429949730), 
     "d_isostamp" : ISODate("2015-04-25T08:15:30.000Z") 
    }, 
    "XBT-USD-stp-nex" : [ 
     { 
      "sellSpread" : -1.80087 
     } 
    ] 
} 
]) 

現在,mongoshell複製上述同樣的操作:

var spreadName = "XBT-USD-stp-nex", 
    start = new Date(2015, 3, 25), 
    end = new Date(2015, 3, 26); 
db.test.aggregate([ 
    { 
     "$match": { 
      "_id.d_isostamp": { "$gte": start, "$lte": end } 
     } 
    }, 
    { 
     "$project": { 
      "sellSpread": "$"+spreadName+".sellSpread" 
     } 
    }/*,<--- deliberately omitted the $unwind stage from the pipeline to replicate the current pipeline 
    { 
     "$unwind": "$sellSpread" 
    }*/, 
    { 
     "$group": { 
      "_id": { 
       "isodate": { "$minute": "$_id.d_isostamp"} 
      }, 
      "rsell_spread": { 
       "$avg": "$sellSpread" 
      } 
     } 
    } 
]) 

輸出

/* 0 */ 
{ 
    "result" : [ 
     { 
      "_id" : { 
       "isodate" : 15 
      }, 
      "rsell_spread" : 0 
     }, 
     { 
      "_id" : { 
       "isodate" : 14 
      }, 
      "rsell_spread" : 0 
     } 
    ], 
    "ok" : 1 
} 

解決方法是在$project步驟之後包含$unwind操作員流水線階段,這將從輸入文檔解構XBT-USD-stp-nex陣列字段併爲每個元素輸出文檔。每個輸出文檔用一個元素值替換數組。這將使$avg組累加器運算符可以工作。

包括這會給聚合結果:

/* 0 */ 
{ 
    "result" : [ 
     { 
      "_id" : { 
       "isodate" : 15 
      }, 
      "rsell_spread" : -1.80083 
     }, 
     { 
      "_id" : { 
       "isodate" : 14 
      }, 
      "rsell_spread" : -1.80081 
     } 
    ], 
    "ok" : 1 
} 

所以在PHP你最後的工作聚集應該是:

$spreadName ='XBT-USD-stp-nex'; 
$pipe = array(
    array(
     '$match' => array(
      '_id.d_isostamp' => array(
       '$gt' => $start, '$lt' => $end 
      ) 
     ) 
    ),  
    array(
     '$project' => array(
      'sellSpread' =>'$'.$spreadName.'.sellSpread', 
     ) 
    ), 
    array('$unwind' => '$sellSpread'), 
    array(
     '$group' => array(
      '_id' => array(
       'isodate' => array(
        '$minute' => '$_id.d_isostamp' 
       ) 
      ), 
      'rsell_spread' => array(
       '$avg' => '$sellSpread' 
      ), 
     ) 
    ), 
); 

$out = $collection->aggregate($pipe ,$options);