【问题标题】:MongoDB count number of new documents per minute based on _idMongoDB 根据 _id 计算每分钟的新文档数
【发布时间】:2013-08-05 14:48:15
【问题描述】:

我想创建一个关于每分钟存储多少新文档的统计数据。

由于标准 ObjectID 的 _id 字段已经包含文档创建的时间戳,我认为应该可以以某种方式使用它。

在 Stackoverflow 上,我发现以下 map reduce 代码可以在有创建数据的专用字段时完成它

Map-Reduce count number of documents in each minute MongoDB

map = function() {

var created_at_minute = new Date(this.created_at.getFullYear(),
                                 this.created_at.getMonth(), 
                                 this.created_at.getDate(), 
                                 this.created_at.getHours(), 
                                 this.created_at.getMinutes());
    emit(created_at_minute, {count: 1});
}

reduce = function(key, values) { 
         var total = 0;
         for(var i = 0; i < values.length; i++) { total += values[i].count; }
         return {count: total};
}

根据 Mongo DB 文档 (http://docs.mongodb.org/manual/reference/object-id/),应该可以通过调用 ObjectId("507f191e810c19729de860ea").getTimestamp() 从 _id 获取时间戳。

现在我不知道是否可以在 map 函数中使用这个 getTimestamp()。

有没有人知道怎么做或者有更好的方法?

我需要它可以在 python 或 php 中实现

【问题讨论】:

  • 地图函数必须用JavaScript编写。我不确定您的意思是“它必须可以在 python 或 php 中实现”?如果_id 是一个ObjectId,那么根据文档,getTimestamp 应该可以正常工作。我不明白你为什么没有尝试过?
  • map reduce 是用 javaskiprt 编写的,我知道,但这必须通过 php 或 python 执行......我现在正在尝试完成一些事情,但我对通过 mongodb 映射 reduce 很陌生

标签: mongodb mapreduce


【解决方案1】:

您确实可以使用 M/R 做到这一点。 getTimestamp() 在 M/R 中工作,因为它在服务器上的 JavaScript 中运行,无论您的客户端语言是 PHP 还是 Python:

map = function() {
    var datetime = this._id.getTimestamp();

    var created_at_minute = new Date(datetime.getFullYear(),
                                     datetime.getMonth(),
                                     datetime.getDate(),
                                     datetime.getHours(),
                                     datetime.getMinutes());
    emit(created_at_minute, {count: 1});
}

reduce = function(key, values) {
    var total = 0;
    for(var i = 0; i < values.length; i++) { total += values[i].count; }
    return {count: total};
}

db.so.mapReduce( map, reduce, { out: 'inline' } );
db.inline.find();

输出类似:

{ "_id" : ISODate("2013-08-05T15:24:00Z"), "value" : { "count" : 9 } }
{ "_id" : ISODate("2013-08-05T15:26:00Z"), "value" : { "count" : 2 } }

但是,我建议您不要使用 M/R,而是转而使用聚合框架,因为它可以使用索引并同时运行,因此速度更快。目前,A/F 还没有操作员从ObjectID 字段中获取时间戳,但您也必须在插入时存储时间。 F.e.像这样的文件:

db.so.drop();
db.so.insert( { date: new ISODate( "2013-08-05T15:24:15" ) } );
db.so.insert( { date: new ISODate( "2013-08-05T15:24:19" ) } );
db.so.insert( { date: new ISODate( "2013-08-05T15:24:25" ) } );
db.so.insert( { date: new ISODate( "2013-08-05T15:24:32" ) } );
db.so.insert( { date: new ISODate( "2013-08-05T15:24:45" ) } );
db.so.insert( { date: new ISODate( "2013-08-05T15:25:15" ) } );
db.so.insert( { date: new ISODate( "2013-08-05T15:25:15" ) } );

db.so.aggregate( [
    { $group: {
        _id: {
            y: { '$year': '$date' },
            m: { '$month': '$date' },
            d: { '$dayOfMonth': '$date' },
            h: { '$hour': '$date' },
            i: { '$minute': '$date' },
        },
        count: { $sum : 1 }
    } } 
] );

哪些输出:

{
    "result" : [
        {
            "_id" : {
                "y" : 2013,
                "m" : 8,
                "d" : 5,
                "h" : 15,
                "i" : 25
            },
            "count" : 2
        },
        {
            "_id" : {
                "y" : 2013,
                "m" : 8,
                "d" : 5,
                "h" : 15,
                "i" : 24
            },
            "count" : 5
        }
    ],
    "ok" : 1
}

【讨论】:

  • 非常感谢,我认为您使用聚合框架可能是对的,map reduce 现在似乎不是 mongo db 的杀手。唯一的缺点是我必须“手动”存储插入时间......
  • 也许在应用聚合框架之前的工作步骤中以某种方式从 _id 中提取时间戳。因此,就像不存在日期一样,提取 _id.getTimestamp 并更新文档应用聚合框架
  • 你知道如何从我试过的子文档“metadata.timestamp”中获取日期 {$project : {timestamp : "$metadata.timestamp"}},
  • Jep 它有效,没有在 shell 中选择正确的集合 ;) 现在我必须考虑如何存储结果,这样我可以节省每次生成新统计的时间
猜你喜欢
  • 2013-06-22
  • 2019-07-03
  • 1970-01-01
  • 1970-01-01
  • 2019-09-28
  • 1970-01-01
  • 1970-01-01
  • 2019-12-18
  • 2021-08-15
相关资源
最近更新 更多