【问题标题】:MongoDB filter an array field by period (start date, end date) using PHPMongoDB 使用 PHP 按期间(开始日期、结束日期)过滤数组字段
【发布时间】:2015-09-30 07:46:42
【问题描述】:

我有这种结构的 MongoDB 文档:

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

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

  • 2015-08-21
  • 2015-09-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)
    ;

感谢您的帮助, 约汉

【问题讨论】:

  • 如果您希望单独测试每个数组元素,那么您需要$elemMatch。不确定教义语法,现在没有任何东西可以测试。但这应该给你一个指针。还正确标记了您的问题,以使其对合适的人可见。

标签: php mongodb mongodb-query doctrine-odm


【解决方案1】:

带聚合

这是 mongoshell 的代码 sn-p 你可以试试

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

      给定以下数据:

      {
           _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 数组。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-01-15
        • 2018-08-19
        • 1970-01-01
        • 2019-11-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多