Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/273.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php Mongodb中的聚合嵌套数组_Php_Mongodb_Mongodb Query_Aggregation Framework - Fatal编程技术网

Php Mongodb中的聚合嵌套数组

Php Mongodb中的聚合嵌套数组,php,mongodb,mongodb-query,aggregation-framework,Php,Mongodb,Mongodb Query,Aggregation Framework,我有一个mongo系列: { "_id":ObjectId("55f16650e3cf2242a79656d1"), "user_id":11, "push":[ ISODate("2015-09-08T11:14:18.285 Z"), ISODate("2015-09-08T11:14:18.285 Z"), ISODate("2015-09-09T11:14:18.285 Z"), IS

我有一个mongo系列:

    {
   "_id":ObjectId("55f16650e3cf2242a79656d1"),
   "user_id":11,
   "push":[
      ISODate("2015-09-08T11:14:18.285      Z"),
      ISODate("2015-09-08T11:14:18.285      Z"),
      ISODate("2015-09-09T11:14:18.285      Z"),
      ISODate("2015-09-10T11:14:18.285      Z"),
      ISODate("2015-09-10T11:14:18.285      Z")
   ]
}{
   "_id":ObjectId("55f15c78e3cf2242a79656c3"),
   "user_id":12,
   "push":[
      ISODate("2015-09-06T11:14:18.285      Z"),
      ISODate("2015-09-05T11:14:18.285      Z"),
      ISODate("2015-09-07T11:14:18.285      Z"),
      ISODate("2015-09-09T11:14:18.285      Z"),
      ISODate("2015-09-09T11:14:18.285      Z"),
      ISODate("2015-09-10T11:14:18.285      Z"),
      ISODate("2015-09-11T11:14:18.285      Z")
   ]
}
如何在单个查询中找到时间戳计数小于3且具有日期(时间戳)>(currentDate-5)的用户标识。我将使用php,不想把所有的文档都放在内存中

说明:

user_id : date       : count
11      : 2015-09-08 : 2
          2015-09-09 : 1
          2015-09-10 : 2

12      : 2015-09-05 : 1
          2015-09-06 : 1
          2015-09-07 : 1
          2015-09-09 : 2
          2015-09-10 : 1
          2015-09-11 : 1

如果日期设置为2015-09-09(用户输入),则用户识别号11将给出3(计数),用户识别号12将给出4(计数)。因此,假设count设置为3(用户输入)。查询应返回11(用户id)。如果count设置为2,则没有可用的用户id;如果count设置为5,则应同时返回11和12。要解决此问题,您需要一个聚合管道,该管道首先将结果“过滤”到“过去5天”,然后基本上对每个符合条件的文档中的数组项的计数进行“求和”,以查看“总数”是否正确“少于三个”

MongoDB聚合的操作符在这方面真的很有帮助,对于从
$map
返回的
false
结果,MongoDB聚合和一些额外的过滤是非常有效的,因为“在文档中首先”和“在”所需的阶段内执行此操作是最有效的处理方法

$result = $collection->aggregate(array(
    array( '$match' => array(
        'push' => array( 
            'time' => array( 
                '$gte' =>  MongoDate( strtotime('-5 days',time()) )
            )
        )     
    )),
    array( '$group' => array(
        '_id' => '$user_id',
        'count' => array(
            '$sum' => array(
                '$size' => array(
                    '$setDifference' => array(
                        array( '$map' => array(
                            'input' => '$push',
                            'as' => 'time',
                            'in' => array(
                                '$cond' => array(
                                    array( '$gte' => array(
                                        '$$time',
                                        MongoDate( strtotime('-5 days',time()) )
                                    )),
                                    '$time',
                                    FALSE
                                )
                            ) 
                        )),
                        array(FALSE)
                    )
                )
            )
        )
    )),
    array( '$match' => array(
        'count' => array( '$lt' => 3 )
    )) 
));
因此,在完成所有工作后,首先通过查找包含符合条件的数组项的“可能”文档,然后在
$group
下查找匹配数组项的“总”大小,然后最终的
$match
排除总大小小于三的所有结果


对于大部分的“JavaScript大脑”(像我一样,受过良好的培训)来说,这基本上就是这样的结构:

db.collection.aggregate([
{“$match”:{
“推送”:{
“$gte”:新日期(新日期().valueOf()-(5*1000*60*60*24))
}
}},
{“$组”:{
“\u id”:“$user\u id”,
“计数”:{
“$sum”:{
“$size”:{
“$setDifference”:[
{“$map”:{
“输入”:“$push”,
“作为”:“时间”,
“在”:{
“$cond”:[
{“$gte”:[
“$$time”,
新日期(
新日期().valueOf()-
( 5 * 1000 * 60 * 60 * 24 )
)
]},
“$$time”,
假的
]
}
}},
[错误]
]
}
}
}
}},
{“$match”:{“count”:{“$lt”:3}}
])
此外,未来版本的MongoDB将提供
$filter
,这简化了整个
$map
$setDifference
语句部分:

db.collection.aggregate([
{“$match”:{
“推送”:{
“$gte”:新日期(新日期().valueOf()-(5*1000*60*60*24))
}
}},
{“$组”:{
“\u id”:“$user\u id”,
“计数”:{
“$sum”:{
“$size”:{
“$filter”:{
“输入”:“$push”,
“作为”:“时间”,
“条件”:{
“$gte”:[
“$$time”,
新日期(
新日期().valueOf()-
( 5 * 1000 * 60 * 60 * 24 )
)                       
]
}
}
}
}
}
}},
{“$match”:{“count”:{“$lt”:3}}
])

还有一点需要注意的是,“日期”可能在“管道定义”之前作为一个单独的变量进行计算,以获得最佳的准确性。

Ouch!。为什么要将一个字段命名为“push”?这几乎是故意造成代码混乱。看起来像是有人“输入错误”。但你真的想只找到“计数”吗“少于三个”的数组项?我所说的推送是指推送通知,有很多类似sms的功能,我想现在可以理解了,这些是发送推送的时间戳。是的,那些大于特定日期的数组项的计数我的观点是,“结果代码”通常看起来像
{“$push”:{“push”:“something”}
(作为JSON表示形式),并且无论如何,对读者来说看起来非常混乱。清晰的字段命名将有助于代码的可读性。这里的另一点是“什么日期”?。你的问题中完全没有这一点,为什么我在评论中问你,而我认为你不清楚。请编辑以告诉我们您未提及的所有“日期标准”。除非您的意思是基本的文档选择,或者您只想“计算”在该时间范围内出现的数组条目吗?我已经更新了这个问题,但之前我写了“在过去5天内,numberOfTimeStamps小于3”,所以“5天”描述的是日期标准。这至少说明了这一点。请理解问题中的表达方式可供解释。因此,可能导致错误的结果/响应。为什么我问。先生,结果是错误的:@lalit去看看前面的一长串评论,你明确地说“时间戳的数量在5天内少于3个”,这正是这里发生的事情,通过“过滤”数组中的时间戳,只返回5天内出现的时间戳。在我至少两次要求您澄清这不是您的意思后,您不仅在更改此“测试”中的标准,而且还说您“期望”阵列中的“完整未过滤”结果。每次“我说的都是