在MongoDB中查找聚合

Pul*_*wal 4 database mongodb node.js mongodb-query aggregation-framework

{
    "_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")

    }]
}
Run Code Online (Sandbox Code Playgroud)

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

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

chr*_*dam 5

您可以使用聚合框架来过滤文档.带有$match和$redact步骤的管道将进行过滤.

考虑运行以下聚合操作,其中$redact允许您$cond使用运算符处理逻辑条件,并使用系统变量$$KEEP"保留"逻辑条件为真的文档,或者$$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;
    });
Run Code Online (Sandbox Code Playgroud)

说明

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

collection.aggregate([
    { '$match': { 'response_log.created_at': { '$gt': last2hours } } }
])
Run Code Online (Sandbox Code Playgroud)

返回的文档将是在"response_log.created_at"当前时间的最后2小时内没有的文件,其中使用API 使用momentjs库last2hours创建变量.subtract


然后,前面的管道$redact将使用$cond三元运算符进一步过滤上面的文档,该运算符计算$size用于获取计数的逻辑表达式,并$filter返回具有与其他逻辑条件匹配的元素的已过滤数组

{ 
    '$lt': [
        {
            '$size': {
                '$filter': {
                    'input': '$response_log',
                    'as': 'res',
                    'cond': { '$lt': ['$$res.created_at', last24hours] }
                }
            }
        },
        3
    ]
}
Run Code Online (Sandbox Code Playgroud)

到$$KEEP文档,如果这个条件为真或$$PRUNE为"删除",其中分析的状态是假文件.


rsp*_*rsp 0

我知道这可能不是您正在寻找的答案,但这可能不是 Mongo 的最佳用例。在关系数据库中很容易做到这一点,在支持 Map/Reduce 的数据库中也很容易做到这一点,但在 Mongo 中则不然。

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

您还可以做的是在 Mongo 中保留一个单独的集合,或者向此处的对象添加一个新属性,该属性将存储添加的活动的最新日期。然后就很容易搜索到你需要的东西了。

当您使用像 Mongo 这样的数据库时,您的数据的外观必须反映您需要用它做什么,就像在本例中一样。添加最后的营销活动日期并在添加的每个营销活动中更新它,可以让您轻松搜索所需的营销活动。

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