【问题标题】:How to match date in aggregate $match using MongoDB and Laravel 5.2?如何使用 MongoDB 和 Laravel 5.2 在聚合 $match 中匹配日期?
【发布时间】:2016-06-16 11:02:15
【问题描述】:

我在 mongodb 集合中有超过 5 万条记录。为了避免 laravel 中的 foreach 循环,我在查询中使用了聚合。

$start = new MongoDate(strtotime("2015-10-01 00:00:00"));
$result = Pms::raw(function ($collection) use($start){
        return $collection->aggregate(array(
            array( '$project' => array( 'EventTS' => 1, 'MainsPower' => 1, '_id' => 0) ),
            array(
                '$unwind' => array(
                    'path' => '$MainsPower',
                    'includeArrayIndex' => "arrayIndex",
                    'preserveNullAndEmptyArrays' => true
                )
            ),
            array(
                '$match' => array(
                    'EventTS' => array(
                        '$gte' => $start
                    )
                )
            ),                
            array(
                '$project' => array(
                    'MainsPower' => 1,
                    'timestamp' => array(
                        '$add' => array(
                            '$EventTS',
                            array( '$multiply' => array( 60000, '$arrayIndex' ) )
                        )
                    )
                )
            )
        ));
    })->toArray();

我需要将日期与集合进行比较,但如果我使用下面的代码,那么我的结果集返回空。

 array(
            '$match' => array(
                'EventTS' => array(
                    '$gte' => $start
                )
            )
        )

使用 Laravel 5.2 在 PHP 中的 mongodb 集合中比较日期的正确方法是什么。

附上示例文件

{ 
    "_id" : ObjectId("576165f58d8b8f39458b456a"), 
    "EventTS" : ISODate("2000-05-11T05:30:00.000+0000"), 
    "PanelID" : "A01000", 
    "MainsPower" : [
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        NumberInt(147), 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null
    ], 
}

{ 
    "_id" : ObjectId("576165f58d8b8f39458b456b"), 
    "EventTS" : ISODate("2016-06-08T18:30:00.000+0000"), 
    "PanelID" : "A01604", 
    "MainsPower" : [
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null, 
        null
    ]
}

【问题讨论】:

    标签: php mongodb laravel-5.2


    【解决方案1】:

    另一种方法是使用 CarboncreateFromDate() 属性来创建日期范围,因为 Laravel 还支持 CarbonDateTime 对象而不是 MongoDate 对象,这些对象将在内部进行转换保存到数据库时为 MongoDate 对象。

    在与上述相同的范围内,您可能希望重组聚合操作,以便 $match 过滤器首先在管道中,在 $unwind 之前操作,这样您就可以优化您的聚合操作,因为EventsTSMainsPower 数组中的一个独立字段(至少从编写代码的方式来看)。

    此外,您不需要最初的项目操作员,因为在管道的后面还有另一个 $project 操作员,它只返回必填字段。

    因此,应用Carbon 包,您可以尝试以下管道:

    $start = Carbon::createFromDate(2015, 10, 1);
    $result = Pms::raw(function ($collection) use($start){
            return $collection->aggregate(array(
                array(
                    '$match' => array(
                        'EventTS' => array(
                            '$gte' => $start
                        )
                    )
                ), 
                array(
                    '$unwind' => array(
                        'path' => '$MainsPower',
                        'includeArrayIndex' => "arrayIndex",
                        'preserveNullAndEmptyArrays' => true
                    )
                ),                           
                array(
                    '$project' => array(
                        'MainsPower' => 1,
                        'timestamp' => array(
                            '$add' => array(
                                '$EventTS',
                                array( '$multiply' => array( 60000, '$arrayIndex' ) )
                            )
                        )
                    )
                )
            ));
        })->toArray();
    

    【讨论】:

    • 我听从了你的指示。我删除了初始投影并在展开之前移动了匹配查询。我也尝试复制粘贴你的代码,但我仍然得到一个空集。@chridam
    • 调试管道的一种方法是只使用第一个管道运算符运行聚合。如果这给出了预期的结果,请添加下一个。在上面的答案中,您首先尝试仅聚合 $match;如果可行,请添加$unwind。这可以帮助您缩小导致问题的运营商的范围。如果问题出在$match 运算符上,请尝试更改范围查询中的日期变量,看看是否有一些日期匹配。
    • 我们尝试一次调试一个元素。使用上述方法似乎对查询的任何日期操作都失败了。它适用于字符串和整数比较。我们尝试了所有运算符进行数据比较,所有运算符都返回一个空集。 @chridam
    • 顺便问一下,您能否通过提供一些可用于复制上述相同问题的示例文档来编辑您的问题?
    • 上传了几个示例文档。
    猜你喜欢
    • 2019-01-24
    • 2015-09-06
    • 1970-01-01
    • 2021-08-12
    • 2020-12-22
    • 1970-01-01
    • 2019-04-15
    • 2015-12-28
    • 1970-01-01
    相关资源
    最近更新 更多