MongoDB使用PHP按周期(开始日期,结束日期)过滤数组字段

时间:2015-09-30 07:46:43

标签: php mongodb mongodb-query doctrine-odm

我有这种结构的MongoDB文档:

{
     _id: 1
     dates: [
         ISODate ("2015-08-21T22: 00: 00Z")
         ISODate ("2015-09-27T22: 00: 00Z")
     ],
     ...
}

在我的示例中,我们看到文档1已被访问:

  • 2015年8月21日
  • 2015年9月27日

在我的申请中,我可以按时间段(开始日期,结束日期)进行过滤。

如果在我的申请中我过滤了期间" 2015-09-01 - 2015-09-01":

逻辑上不应该找到文件1,因为在此期间没有查阅过。但是通过我的测试,找到了文档1.

我必须使用什么条件来正确过滤数据?

我试过了,但这是错误的:

<?php
$begin = new \DateTime('2015-09-01');
$end = new \DateTime('2015-09-01');

$expr1 = $qb->expr()->field('dates')->gte($begin);
$expr2 = $qb->expr()->field('dates')->lte($end);

$qb
    ->addAnd($expr1)
    ->addAnd($expr2)
    ;

感谢您的帮助, Yohann

3 个答案:

答案 0 :(得分:0)

汇总

这是你可以尝试的mongoshell的代码片段

> db.collection.aggregate([{$unwind:"$dates"},{$match:{"dates":{$gt:new ISODate("2015-01-01"),$lt:new ISOD
ate("2015-09-01")}}}])

使用查询查询

db.collection.find({dates:{$elemMatch:{$gt:new ISODate("2015-01-10"),$lt:new ISODate("2015-09-01")}}},{"dates.$":1})

答案 1 :(得分:0)

谢谢大家,我用你的答案解决了问题,经过全面测试。

使用教义odm做到这一点很难,这是解决方案:

<?php
$begin = new \DateTime($options['begin']);
$end = new \DateTime($options['end']);

$expr = $qb->expr()
    ->gte($begin)
    ->lte($end)
;

$exprElementMatch = $qb->expr()->field('dates')->elemMatch($expr);
$qb->addAnd($exprElementMatch);

答案 2 :(得分:0)

目前标记为已解决的答案实际上并不适用于我。

鉴于以下数据:

{
     _id: 1
     dates: [
         ISODate("2015-08-21T22:01:12Z")
         ISODate("2015-08-22T00:06:45Z")
     ],
     ...
}

以下查询与上述文档匹配:

db.collection.find({dates:{$elemMatch:{$gt:new ISODate("2017-08-21"),$lt:new ISODate("2017-08-22")}}}

我很困惑并阅读了$elemMatch documentation并说明了:

  

$ elemMatch运算符将查询结果中字段的内容限制为仅包含与$ elemMatch条件匹配的第一个元素。

因此,根据这个已解决的问题,这根本无法正常工作。对于我的用例,我能够仅使用以下查询来评估dates数组中的第一个元素来过滤我的文档。

db.collection.find({"dates.0":{$gte:new ISODate("2017-07-02"),$lt:new ISODate("2017-07-03")})

This answer详细介绍了如何实际查询dates数组。