2015-05-06 56 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);