【问题标题】:Find count of maximum consecutive records based on one field in Mongodb Query根据 Mongodb Query 中的一个字段查找最大连续记录数
【发布时间】:2014-03-04 12:15:53
【问题描述】:

我想根据一个特定字段查找最大连续记录数。

找到基于字段的排序后我的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 文档,特别是如何在上述场景中应用它。

【问题讨论】:

  • 您能否澄清您的意思是按特定关键字段排序时的“最连续记录”,还是您正在寻找自然的插入顺序。如果人们在提出问题时了解您的用例,这会有所帮助。这样可以避免您稍后说响应不是您想要的。
  • @NeilLunn:请检查我更新的问题。
  • 你可以用javascript表达式来实现(注意会很慢)。据我所知,没有 mongo 原生查询。
  • 这些真的有增量数字 _id 吗? _id 是排序键吗?我对太容易的事情持怀疑态度。
  • @NeilLunn:'updated_at' 是排序键,'_id' 不是增量数值。

标签: mongodb mapreduce mongoid


【解决方案1】:

你可以做这个mapReduce操作。

首先是映射器:

var mapper = function () {


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

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

};

它会记录在标志中看到true 值的总次数。如果该计数大于 1,则我们发出该值,还包含文档 _id。当标志为false 时,另一个用于键的计数器会递增,以便为匹配项设置一个分组“键”。

然后是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 函数,我们定义了“范围”中使用的全局变量,并传入updated_at 日期所需的“排序”。结果如下:

{
    "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 的问题,现在你有一个例子。

【讨论】:

  • 感谢您的回复。
  • @NeilLunn,很好的答案,你在哪里?
猜你喜欢
  • 2014-12-04
  • 2022-08-18
  • 2021-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多