0

我有一个包含大约 600k 文档的 mongo 集合。我正在枚举集合,按_id 排序。但是,文档不会按该排序顺序返回。它们似乎根据 ObjectId 的时间戳部分正确排序,但不是根据 pid 字段。

这是我用来重现这个的 c# 代码:

var cursor = m_collection.FindAll().SetSortOrder(SortBy.Ascending("_id"));

ObjectId previous = ObjectId.Empty;

foreach (var document in cursor)
{
    var id = document[IdField].AsObjectId;

    Throw.Assert(id > previous, "Sort order is invalid!");
    previous = id;
}

在某些时候,断言被触发。我可以看到新的 id 与前一个具有相同的时间戳,但 pid 较低。

我原以为使用 {"_id":1} 进行排序将使用 ObjectIds 的所有组件进行排序,而不仅仅是时间戳。

服务器对 ObjectId 使用的比较算法是否与 C# 客户端的 ObjectId.CompareTo 不同?

4

1 回答 1

0

MongoDB C# 的源代码CompareTo目前在此处。该代码将ObjectId一路的每个元素与 3 字节计数器进行比较。鉴于ObjectId的性质,其中包含:

  • 一个 4 字节的值,表示自 Unix 纪元以来的秒数
  • 一个 3 字节的机器标识符
  • 一个 2 字节的进程 ID
  • 和一个 3 字节的计数器,从一个随机值开始

超出时间戳进行排序是没有意义的。虽然CompareTo它是准确的并且会产生一致的结果,但可能无法以符合您期望的方式进行排序。

鉴于会有两个对象在相同的时间戳(4 字节值)创建的情况,那么CompareTo在 C# 中的工作方式下,结果会有一些差异。因此,执行您所做的断言会导致一些令人困惑的结果,不应将其用作检测乱序结果的方法。

大多数驱动程序在不存在时创建_id/值(包括 C# 驱动程序)。ObjectId除了时间戳之外,您真的没有什么可以排序的。

你可以这样做:

Throw.Assert(id.Timestamp > previous.Timestamp, "Sort order is invalid!");
于 2013-04-04T17:32:30.030 回答