在Mongodb查询中,基于一个字段查找最大连续记录的数量

7

我希望找到特定字段的最大连续记录计数。

在对字段进行排序后,我的db.people集合如下:

> db.people.find().sort({ updated_at: 1})
{ "_id" : 1, "name" : "aaa", "flag" : true, "updated_at" : ISODate("2014-02-07T08:42:48.688Z") }
{ "_id" : 2, "name" : "bbb", "flag" : false, "updated_at" : ISODate("2014-02-07T08:43:10Z") }
{ "_id" : 3, "name" : "ccc", "flag" : true, "updated_at" : ISODate("2014-02-07T08:43:40.660Z") }
{ "_id" : 4, "name" : "ddd", "flag" : true, "updated_at" : ISODate("2014-02-07T08:43:51.567Z") }
{ "_id" : 6, "name" : "fff", "flag" : false, "updated_at" : ISODate("2014-02-07T08:44:23.713Z") }
{ "_id" : 7, "name" : "ggg", "flag" : true, "updated_at" : ISODate("2014-02-07T08:44:44.639Z") }
{ "_id" : 8, "name" : "hhh", "flag" : true, "updated_at" : ISODate("2014-02-07T08:44:51.415Z") }
{ "_id" : 5, "name" : "eee", "flag" : true, "updated_at" : ISODate("2014-02-07T08:55:24.917Z") }

在上述记录中,有两个地方连续出现flag属性值为true。即
record with _id 3 - record with _id 4   (2 consecutive records)

并且

record with _id 7 - record with _id 8 - record with _id 5  (3 consecutive records)

然而,我想要从Mongo查询搜索中获取最大连续数字,即3。是否可能获得这样的结果?我谷歌了一下,并在这里找到了一个类似的解决方案,使用Map-Reduce,链接如下:https://stackoverflow.com/a/7408639/1120530。我是Mongodb的新手,无法理解map-reduce文档,特别是如何将其应用于上述情况。

你能否澄清一下,当按特定键字段排序时,您是否指的是“最连续记录”,还是寻找插入的自然顺序。在提问时,让人们了解您的用例会很有帮助。这可以避免您后来说回答并不完全符合您的要求。 - Neil Lunn
这些是否真的具有增量数字_id?而且_id是排序键,对吧?我对太容易的事情持怀疑态度。 - Neil Lunn
@NeilLunn:'updated_at' 是排序键,而 '_id' 不是递增的数字值。 - Dhanu Gurung
很抱歉比预期回复晚了这么多,但我认为答案应该足够了。 - Neil Lunn
我们可以看到自从答案提交以来,您已经多次访问了该网站。如果这不符合您的期望,请发表评论。当您实际收到答案时,放弃赏金所获得的声誉点似乎是一件遗憾的事情。 - Neil Lunn
显示剩余2条评论
1个回答

5
你可以执行此MapReduce操作。
首先是mapper:
var mapper = function () {


    if ( this.flag == true ) {
        totalCount++;
    } else {
        totalCount = 0;
    }

    if ( totalCount != 0 ) {
        emit (
        counter,
        {  _id: this._id, totalCount: totalCount }
    );
    } else {
      counter++;
    }

};

该代码追踪了变量flag中出现true值的次数。如果该次数超过了1,则输出包含文档_id的值。当flag为false时,另一个计数器被递增,以便为匹配项创建一个分组“key”。

然后是reducer:

var reducer = function ( key, values ) {

    var result = { docs: [] };

    values.forEach(function(value) {
        result.docs.push(value._id);
        result.totalCount = value.totalCount;
    });

    return result;

};

_id值与totalCount一起推入结果数组中。

然后运行:

db.people.mapReduce(
    mapper,
    reducer,
   { 
       "out": { "inline": 1 }, 
       "scope": { 
           "totalCount": 0, 
           "counter": 0 
       }, 
       "sort": { "updated_at": 1 } 
   }
)

因此,我们使用mapperreducer函数,然后定义在"scope"中使用的全局变量,并传入所需的基于updated_at日期进行排序的"sort"。 这给出了以下结果:

{
    "results" : [
        {
            "_id" : 1,
            "value" : {
                "docs" : [
                     3,
                     4
                 ],
                 "totalCount" : 2
            }
        },
        {
            "_id" : 2,
            "value" : {
            "docs" : [
                7,
                8,
                5
             ],
             "totalCount" : 3
             }
        }
    ],
    "timeMillis" : 2,
    "counts" : {
            "input" : 7,
            "emit" : 5,
            "reduce" : 2,
            "output" : 2
    },
    "ok" : 1,
}

当然,你可以跳过totalCount变量,直接使用数组长度,这是一样的。但既然你想要使用计数器,那就加上它吧。但这就是原则。

所以,是的,这个问题适合使用mapReduce,现在你有了一个例子。


谢谢回复。 - Dhanu Gurung
@NeilLunn,回答得不错,你在哪儿啊? - Disposer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接