MongoDB - 获取文档最新版本的最有效方法

时间:2012-01-30 20:20:06

标签: mongodb nosql

我正在使用MongoDB来保存一组文档。

每个文档都有一个_id(版本),它是一个ObjectId。每个文档都有一个documentId,它在不同版本之间共享。这也是在创建第一个文档时分配的OjectId。

在给定documentId的情况下,找到最新版本文档的最有效方法是什么?

即。我想得到_id = max(_id)和documentId = x

的记录

我需要使用MapReduce吗?

提前致谢,

山姆

2 个答案:

答案 0 :(得分:6)

添加包含两个字段(documentId,_id)的索引,不要使用max(for for)?使用documentId = x查询,按_id命令DESC,限制(1)结果获取最新信息。记住索引的正确排序顺序(也是DESC)

像这样的东西

db.collection.find({documentId : "x"}).sort({_id : -1}).limit(1)

其他方法(更加非规范化)将使用其他集合,例如:

{
    documentId : "x",
    latestVersionId : ...
}

使用原子操作可以安全地更新此集合。添加适当的索引会使查询快速闪电。

有一件事需要考虑 - 我不确定ObjectID是否总能被安全地用于订购最新版本。使用时间戳可能更加确定。

答案 1 :(得分:1)

我使用sortlimit输入与Daimon的第一个答案相同的答案。这可能不推荐,特别是对于某些驱动程序(使用随机数而不是最低有效部分的增量),因为生成了_id的方式。它具有第二[与较小的,如毫秒]的分辨率作为最重要的部分,但最后一个数字可以是随机数。因此,如果您有一个用户在一秒钟内保存两次(可能不太可能,但值得注意),您可能会得到一个稍微有序的最新文档。

有关ObjectID结构的更多详细信息,请参阅http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-BSONObjectIDSpecification

我建议在文档中添加一个显式的versionNumber字段,这样你就可以使用该字段以类似的方式进行查询,如下所示:

db.coll.find({documentId: <id>}).sort({versionNum: -1}).limit(1);

编辑以回答评论中的问题

您可以直接在MongoDB中存储常规DateTime,但它只会在MongoDB中以“DateTime”格式存储毫秒精度。如果这足够好,那就更容易了。

BsonDocument doc = new BsonDocument("dt", DateTime.UtcNow);
coll.Insert (doc);
doc = coll.FindOne();
// see it doesn't have precision...
Console.WriteLine(doc.GetValue("dt").AsUniversalTime.Ticks);

如果你想要.NET DateTime(滴答)/时间戳精度,你可以做一堆强制转换来使它工作,如:

BsonDocument doc = new BsonDocument("dt", new BsonTimestamp(DateTime.UtcNow.Ticks));
coll.Insert (doc);
doc = coll.FindOne();
// see it does have precision
Console.WriteLine(new DateTime(doc.GetValue("dt").AsBsonTimestamp.Value).Ticks);

再次更新!

看起来BsonTimestamp的真正用途是在第二个分辨率内生成唯一的时间戳。所以,你不应该像我在最后几行代码中那样滥用它们,它实际上可能会搞砸结果的排序。如果你需要以Tick(100纳秒)的分辨率存储DateTime,你可能应该只存储64位int“ticks”,它可以在mongodb中排序,然后在你将它拉出之后将它包装在DateTime中数据库再次如此:

BsonDocument doc = new BsonDocument("dt", DateTime.UtcNow.Ticks);
coll.Insert (doc);
doc = coll.FindOne();
DateTime dt = new DateTime(doc.GetValue("dt").AsInt64);
// see it does have precision  
Console.WriteLine(dt.Ticks);