【问题标题】:Mongo: get the nth document by creation dateMongo:按创建日期获取第 n 个文档
【发布时间】:2015-06-02 05:58:56
【问题描述】:

我整个上午都在寻找解决方案,但找不到可以在生产环境中使用的任何东西。

最终目标是,给定一个 mongo 集合,获取 N 条最旧的消息,并对它们应用更新。这不容易做到,比如

db.coll.update({}, {$set: {status: 'UPDATED'}}).limit(N)

不工作。

所以请记住,我想更新这 N 个文档(或者如果它的文档少于 N 个,则更新整个集合),我正在考虑按创建日期对文档进行排序,获取第 N 个文档,然后更新所有文档 $lte _id(N)。 (带有漂亮的伪代码)。

问题是,我似乎无法找到有效的方法来做到这一点。首先我尝试了类似的东西:

db.coll.find().sort(_id: 1).limit(N).sort(_id: -1).limit(1)

然后意识到在同一命令中有两个排序是没用的......

这行得通:

db.coll.find().limit(N).skip(N-1).next()

但有两大缺点:

  • 我必须事先确定我至少有 N 个文档(在我的情况下这不是什么大问题,但是...)
  • .skip() 众所周知是 CPU 密集型的,因为它实际上会遍历整个游标。虽然在我的情况下 N 不应该大于 1M,但仍然不是一件好事,当我真正想要的是光标的最后一个文档时。

所以我想我的问题是,假设我尝试使用创建日期来做到这一点是正确的方法,我该怎么做:

  • 在我的集合中插入第 N 个文档(在某些条件下)
  • 如何获取光标的最后一条记录 (db.coll.find().limit(N))

非常感谢!! 亚历克西斯

PS:如果这有什么不同的话,我们实际上是在用 Java 编写代码。

【问题讨论】:

  • 是和不是。我不想有我的百万个请求并像解决方案那样手动处理它们。我们正在谈论的数字太大,无法真正优雅地处理我的 Java 驱动程序:/ 如果这是任何人提供的唯一解决方案,我会尝试它,但获取光标的最后一个元素应该不难对吗?
  • 还有一个更接近您的问题的问题:stackoverflow.com/questions/12572485/…。该解决方案基本上建议为您的日期使用自动递增字段并为其编制索引,然后您可以在那里更新第 n 个日期。当然,这种方法的实用性取决于您如何收集数据(即,您是否以线性方式收集数据)。
  • 当 id 已经包含一个日期时添加一个字段感觉很愚蠢,因此我们应该能够使用一个订单:/

标签: mongodb


【解决方案1】:

使用 map-reduce,您可以几乎获得想要的结果。

mapreduce 函数很简单:

map = function() {
  this.value.status = 'UPDATED';
  emit(this._id, this.value)
}

reduce = function(key, values) {
  // XXX should log an error if we reach that point
  return {unexpectedReduce: values}
}

技巧是使用mapReducemerge output action(以及limitsortquery 仅选择所需的输入文档):

db.test.mapReduce(map, reduce,
                  { query: {"value.status": {$ne: 'UPDATED'}},
                    sort: { _id: 1 },
                    limit: 10,
                    out: {merge: 'test'},
                  }
)

但是,有一个但是:您必须将文档存储为{_id: ... , value: { field1: ..., field2: ..., ... }},因为这是the only output format currently supported by mapReduce jobs


这是我在编写此答案时使用的示例测试集:

> for(i = 0; i < 100; ++i) {
    db.test.insert({value:{field1: i, field2: "hello"+i}}); sleep(500);
  }

(顺便说一句,注意我使用ObjectID 来识别旧文档,因为 4 个最重要的字节是自 Unix 纪元以来的秒数)

运行上述 map-reduce 作业将按 10 条较旧的未更新记录批量更新集合:

> db.test.mapReduce(map, reduce,
                  { query: {"value.status": {$ne: 'UPDATED'}},
                    sort: { _id: 1 },
                    limit: 10,
                    out: {merge: 'test'},
                  }
)
> db.test.find()
{ "_id" : ObjectId("556cd4d00027c9fdf8af809f"), "value" : { "field1" : 96, "field2" : "hello96" } }
{ "_id" : ObjectId("556cd4d00027c9fdf8af80a0"), "value" : { "field1" : 97, "field2" : "hello97" } }
{ "_id" : ObjectId("556cd4d10027c9fdf8af80a1"), "value" : { "field1" : 98, "field2" : "hello98" } }
{ "_id" : ObjectId("556cd4d10027c9fdf8af80a2"), "value" : { "field1" : 99, "field2" : "hello99" } }
{ "_id" : ObjectId("556cd49f0027c9fdf8af803f"), "value" : { "field1" : 0, "field2" : "hello0", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a00027c9fdf8af8040"), "value" : { "field1" : 1, "field2" : "hello1", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a00027c9fdf8af8041"), "value" : { "field1" : 2, "field2" : "hello2", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a10027c9fdf8af8042"), "value" : { "field1" : 3, "field2" : "hello3", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a10027c9fdf8af8043"), "value" : { "field1" : 4, "field2" : "hello4", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a20027c9fdf8af8044"), "value" : { "field1" : 5, "field2" : "hello5", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a20027c9fdf8af8045"), "value" : { "field1" : 6, "field2" : "hello6", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a30027c9fdf8af8046"), "value" : { "field1" : 7, "field2" : "hello7", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a30027c9fdf8af8047"), "value" : { "field1" : 8, "field2" : "hello8", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a40027c9fdf8af8048"), "value" : { "field1" : 9, "field2" : "hello9", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a40027c9fdf8af8049"), "value" : { "field1" : 10, "field2" : "hello10" } }
...

向右滚动查看上面和下面代码块中的更新状态

然后再次运行相同的 mapReduce 作业:

{ "_id" : ObjectId("556cd4d00027c9fdf8af809f"), "value" : { "field1" : 96, "field2" : "hello96" } }
{ "_id" : ObjectId("556cd4d00027c9fdf8af80a0"), "value" : { "field1" : 97, "field2" : "hello97" } }
{ "_id" : ObjectId("556cd4d10027c9fdf8af80a1"), "value" : { "field1" : 98, "field2" : "hello98" } }
{ "_id" : ObjectId("556cd4d10027c9fdf8af80a2"), "value" : { "field1" : 99, "field2" : "hello99" } }
{ "_id" : ObjectId("556cd49f0027c9fdf8af803f"), "value" : { "field1" : 0, "field2" : "hello0", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a00027c9fdf8af8040"), "value" : { "field1" : 1, "field2" : "hello1", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a00027c9fdf8af8041"), "value" : { "field1" : 2, "field2" : "hello2", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a10027c9fdf8af8042"), "value" : { "field1" : 3, "field2" : "hello3", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a10027c9fdf8af8043"), "value" : { "field1" : 4, "field2" : "hello4", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a20027c9fdf8af8044"), "value" : { "field1" : 5, "field2" : "hello5", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a20027c9fdf8af8045"), "value" : { "field1" : 6, "field2" : "hello6", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a30027c9fdf8af8046"), "value" : { "field1" : 7, "field2" : "hello7", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a30027c9fdf8af8047"), "value" : { "field1" : 8, "field2" : "hello8", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a40027c9fdf8af8048"), "value" : { "field1" : 9, "field2" : "hello9", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a40027c9fdf8af8049"), "value" : { "field1" : 10, "field2" : "hello10", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a50027c9fdf8af804a"), "value" : { "field1" : 11, "field2" : "hello11", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a50027c9fdf8af804b"), "value" : { "field1" : 12, "field2" : "hello12", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a60027c9fdf8af804c"), "value" : { "field1" : 13, "field2" : "hello13", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a60027c9fdf8af804d"), "value" : { "field1" : 14, "field2" : "hello14", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a70027c9fdf8af804e"), "value" : { "field1" : 15, "field2" : "hello15", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a70027c9fdf8af804f"), "value" : { "field1" : 16, "field2" : "hello16", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a80027c9fdf8af8050"), "value" : { "field1" : 17, "field2" : "hello17", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a80027c9fdf8af8051"), "value" : { "field1" : 18, "field2" : "hello18", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a90027c9fdf8af8052"), "value" : { "field1" : 19, "field2" : "hello19", "status" : "UPDATED" } }
{ "_id" : ObjectId("556cd4a90027c9fdf8af8053"), "value" : { "field1" : 20, "field2" : "hello20" } }
{ "_id" : ObjectId("556cd4aa0027c9fdf8af8054"), "value" : { "field1" : 21, "field2" : "hello21" } }
...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-12
    • 1970-01-01
    • 2011-06-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多