在MongoDB中查找聚合

时间:2017-04-25 08:44:36

标签: node.js mongodb mongodb-query aggregation-framework database

{
    "_id" : ObjectId("5852725660632d916c8b9a38"),
    "response_log" : [ 
    {
        "campaignId" : "AA",
        "created_at" : ISODate("2016-12-20T11:53:55.727Z")
    }, 
    {
        "campaignId" : "AB",
        "created_at" : ISODate("2016-12-20T11:55:55.727Z")

    }]
}

我有一个包含数组的文档。我想从当前时间过去2小时内选择所有没有response_log.created_at的文档,并且最后24个中的response_log.created_at计数小于3。

我无法弄清楚如何去做。请帮忙

2 个答案:

答案 0 :(得分:5)

您可以使用聚合框架来过滤文档。具有 $match $redact 步骤的管道将执行过滤。

考虑运行以下聚合操作,其中 $redact 允许您使用 $cond 运算符处理逻辑条件并使用系统变量< strong> $$KEEP “保留”逻辑条件为true的文档或 $$PRUNE 以“删除”条件为false的文档。

此操作类似于具有 $project 管道,该管道选择集合中的字段并创建一个新字段,其中包含逻辑条件查询的结果,然后是后续的 $match ,但 $redact 使用更高效的单个管道阶段:

var moment = require('moment'),
    last2hours = moment().subtract(2, 'hours').toDate(),
    last24hours = moment().subtract(24, 'hours').toDate();

MongoClient.connect(config.database)
    .then(function(db) {
        return db.collection('MyCollection')
    })
    .then(function (collection) {
        return collection.aggregate([
            { '$match': { 'response_log.created_at': { '$gt': last2hours } } },
            { 
                '$redact': {
                    '$cond': [
                        { 
                            '$lt': [
                                {
                                    '$size': {
                                        '$filter': {
                                            'input': '$response_log',
                                            'as': 'res',
                                            'cond': { 
                                                '$lt': [
                                                    '$$res.created_at', 
                                                    last24hours
                                                ] 
                                            }
                                        }
                                    }
                                },
                                3
                            ]
                        },
                        '$$KEEP',
                        '$$PRUNE'
                    ]
                }
            }
        ]).toArray();  
    })
    .then(function(docs) {
        console.log(docs)
    })
    .catch(function(err) {
        throw err;
    });

说明

在上面的汇总操作中,如果您执行第一个 $match 管道步骤

collection.aggregate([
    { '$match': { 'response_log.created_at': { '$gt': last2hours } } }
])

返回的文件将是当前时间内使用 {momentjs库创建变量"response_log.created_at"的最近2小时内没有last2hours的文件{3}} API。

使用 subtract 的前一个管道将使用 $redact 三元运算符进一步过滤上述文档,该运算符用于评估此逻辑表达式使用 $cond 获取计数,使用 $size 返回包含与其他逻辑条件匹配的元素的已过滤数组

{ 
    '$lt': [
        {
            '$size': {
                '$filter': {
                    'input': '$response_log',
                    'as': 'res',
                    'cond': { '$lt': ['$$res.created_at', last24hours] }
                }
            }
        },
        3
    ]
}
如果此条件为真,则

$filter 文档; $$KEEP 以“删除”评估条件为false的文档。< / p>

答案 1 :(得分:0)

我知道这可能不是您正在寻找的答案,但这可能不是Mongo的最佳用例。在关系数据库中很容易做到这一点,在支持map / reduce的数据库中很容易做到这一点,但在Mongo中它并不简单。

如果您的数据看起来不同,并且您将每个日志条目保存为引用该对象的单独文档(在这种情况下为id 5852725660632d916c8b9a38)而不是其中的一部分,那么您可以对最新的日志条目进行简单查询有那个id。如果我打算使用Mongo(我不会这样做),这就是我在你的情况下会做的事情。

您还可以做的是在Mongo中保留一个单独的集合,或者在此处拥有的对象中添加一个新属性,该对象将存储添加的最新广告日期。那么搜索你需要的东西会很容易。

当您使用像Mongo这样的数据库时,数据的外观必须反映出您需要使用它的方式,就像在这种情况下一样。添加最后一个广告系列日期并在添加的每个广告系列中进行更新都可以让您轻松搜索所需的广告系列。

如果您希望能够进行任何搜索和聚合,那么最好使用关系数据库。