Php 数组元素聚合中的mongodb avg

Php 数组元素聚合中的mongodb avg,php,mongodb,Php,Mongodb,我有以下收集结构 { "_id": { "d_timestamp": NumberLong(1429949699), "d_isostamp": ISODate("2015-04-25T08:14:59.0Z") }, "XBT-USD-cpx-okc": [ { "buySpread": -1.80081 } { "_id": { "isodate": ISODate("2015-04-25T08:00:58.0Z

我有以下收集结构

{
   "_id": {
     "d_timestamp": NumberLong(1429949699),
     "d_isostamp": ISODate("2015-04-25T08:14:59.0Z")
   },
   "XBT-USD-cpx-okc": [
   {
       "buySpread": -1.80081
   }
{
  "_id": {
     "isodate": ISODate("2015-04-25T08:00:58.0Z")
  },
  "rsell_spread": [
     -4.49996▼
  ]
}
我运行以下聚合

$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);
结果是,
rsell_spread
的值为0,而如果我在
$group
中运行
$max
而不是
$avg
,我会得到
rsell_spread
的准确值,具有以下结构

{
   "_id": {
     "d_timestamp": NumberLong(1429949699),
     "d_isostamp": ISODate("2015-04-25T08:14:59.0Z")
   },
   "XBT-USD-cpx-okc": [
   {
       "buySpread": -1.80081
   }
{
  "_id": {
     "isodate": ISODate("2015-04-25T08:00:58.0Z")
  },
  "rsell_spread": [
     -4.49996▼
  ]
}
所以我有两个问题:

1/为什么
$avg
功能不工作

2/例如,当我使用
$max
时(仅使用一个常规数字),我如何能够使结果不在数组中

  • 组累加器操作符确实有效,只是在您的情况下,它被应用于数组中的一个元素,从而给出了“不正确”的结果

  • 使用group accumulator运算符时,它返回将表达式应用于文档组中的每个文档所产生的最高值,因此在您的示例中,它返回了最大数组

  • 演示这一点,考虑在蒙哥马尔的测试集合中添加一些示例文档:

    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
            }
        ]
    }
    ])
    
    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"
                }
            }
        }
    ])
    
    现在,在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
            }
        ]
    }
    ])
    
    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"
                }
            }
        }
    ])
    
    解决方案是在步骤后包括一个操作员管道阶段,这将从输入文档解构
    XBT USD stp nex
    数组字段,并为每个元素输出一个文档。每个输出文档都用元素值替换数组。这将使组累加器操作员能够工作

    包括此项将给出聚合结果:

    /* 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);