【问题标题】:Find rows between two dates that are an interval n apart查找间隔为 n 的两个日期之间的行
【发布时间】:2015-07-19 13:57:40
【问题描述】:

假设我在一年中的每一天(或可能每小时、每分钟……)都有一个条目。我想要做的是查询两个日期范围内的所有行,并且每个间隔只返回一个条目 n (例如,每周一个条目或每隔一天一个条目,. ..)

举个更具体的例子,我的数据库有这样的条目:

{ _id: ..., date: ISODate("2014-07-T01:00:00Z"), values: ... }
{ _id: ..., date: ISODate("2014-07-02T12:00:00Z"), values: ... }
...
{ _id: ..., date: ISODate("2015-03-17T12:00:00Z"), values: ... }
{ _id: ..., date: ISODate("2015-03-18T12:00:00Z"), values: ... }

我想要2014-12-052015-02-05 之间的每个结果,但每个3 days 只需要一个结果。结果集应如下所示:

{ _id: ..., date: ISODate("2014-12-05T12:00:00Z"), values: ... }
{ _id: ..., date: ISODate("2014-12-08T12:00:00Z"), values: ... }
{ _id: ..., date: ISODate("2014-12-11T12:00:00Z"), values: ... }
{ _id: ..., date: ISODate("2014-12-14T12:00:00Z"), values: ... }
...

这可以通过某种方式完成吗?

【问题讨论】:

    标签: mongodb date mongodb-query date-range


    【解决方案1】:

    使用聚合框架(和一个非常复杂的查询),您可以实现您的目标。大致如下:

    db.coll.aggregate([
        {$match: {
            date: {
                $gte: ISODate("2014-12-08T12:00:00.000Z"),
                $lt: ISODate("2014-12-12T00:00:00.000Z")
            }
        }},
        {$project:
            { date:1,
              value: 1,
              grp: { $let: 
                     {
                       vars: { delta:{$subtract:["$date", ISODate("2014-12-08T12:00:00.000Z")]}},
                       in: {$subtract:["$$delta", {$mod:["$$delta",3*24*3600*1000]}]}
                     }
                   }
            }
        },
        {$sort: { date: 1 }},
        {$group: {_id:"$grp", date: {$first:"$date"}, value: {$first: "$value"}}}
    ])
    
    • $match 步骤将只保留所需范围内的行;
    • project 步骤将保留日期和值,并将根据日期计算“组号”。 delta 是给定日期与某个任意应用程序相关来源之间的时间差(以毫秒为单位)。由于 MongoDB 没有 整数除法 运算符,我使用了一个替代:delta-mod(delta, 3*24*3600*1000)。这将每 3 天更改一次(3 天 × 24 小时 × 3600 秒 × 1000 毫秒);
    • $sort 步骤可能不是必需的,具体取决于您的用例。我使用它是为了确保在下一步中保留每个组的 first 日期和值时的确定性结果;
    • 最后 (!)$group 将按之前计算的 grp 值对文档进行分组,只保留每个组的第一个日期和值。

    【讨论】:

    • 谢谢!这工作得很好:) 我还考虑过抓取所有行并在我的程序中手动过滤它们。有些表每天只有一个条目,间隔只有 2-7 天。您知道大数据集的查询性能可能如何吗?
    • @KeVin 总是很难先验谈论性能。但在这里,我想说整个事情取决于$match 步骤。在必填字段上有一个索引,并且如果通过其他阶段的文档数量不是太多,这应该表现得不错。也就是说,只有对您的实际数据集进行适当的基准测试才能给您一个明确的答案。
    【解决方案2】:

    您可以使用以下语法查询范围:

    db.collection.find( { field: { $gt: value1, $lt: value2 } } );
    

    在您的情况下,字段将是日期字段,这个问题可能会帮助您格式化值:

    return query based on date

    编辑:我没有看到检索每个第 n 个文档的要求。在这种情况下,我不确定 MongoDB 是否内置了对此的支持。您可能必须自己操作返回的数组。在这种情况下,一旦获得范围,您就可以按索引过滤。这是一些样板文件(我无法弄清楚 Array.prototype.filter 的有效使用,因为该函数消除了对索引的需求 - 与您想要的相反。):

    var result =[]
    for (var i = 0; i < inputArray.length ; i+=3) {     
        result.push(numList[i]);        
    }
    return result;
    

    【讨论】:

    • 这里的关键问题是按3天分组。
    • 啊,是的,我的错。在我收集到问题的所有要求之前,我超前并开始回答(这个行业值得学习的宝贵经验)。我会用可能的解决方案修改我的问题
    猜你喜欢
    • 1970-01-01
    • 2015-08-06
    • 1970-01-01
    • 2020-07-19
    • 1970-01-01
    • 2018-02-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多