MongoDB 使用 PHP 按时间段(开始日期、结束日期)过滤数组字段

MongoDB filter an array field by period (start date, end date) using PHP

我有 MongoDB 个具有这种结构的文档:

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

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

在我的应用程序中,我可以按时间段(开始日期、结束日期)进行过滤。

如果在我的应用程序中我过滤了时间段“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)
    ;

感谢您的帮助, 约翰

有聚合

这是 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})

谢谢大家,我根据你们的回答解决了问题,完全测试了。

用 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);

当前标记为已解决的答案实际上对我不起作用。

给定以下数据:

{
     _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 并指出:

The $elemMatch operator limits the contents of an field from the query results to contain only the first element matching the $elemMatch condition.

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

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

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