Php Mongodb中的聚合嵌套数组
我有一个mongo系列: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
{
"_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天内出现的时间戳。在我至少两次要求您澄清这不是您的意思后,您不仅在更改此“测试”中的标准,而且还说您“期望”阵列中的“完整未过滤”结果。每次“我说的都是