带有排序顺序的Mongo查询以不正确的顺序返回文档

时间:2013-04-04 15:56:28

标签: mongodb

我有一个mongo集合,大约有600k文档。我正在枚举该集合,按_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与前一个id具有相同的时间戳,但是pid较低。

我原本以为使用{“_ id”:1}进行排序会使用ObjectIds的所有组件进行排序,而不仅仅是时间戳。

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

1 个答案:

答案 0 :(得分:0)

MongoDB C#CompareTo的来源目前为here。代码将ObjectId的每个元素一直比较为3字节计数器。鉴于包含ObjectId的性质:

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

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

假设存在两个对象在同一时间戳(4字节值)创建的情况,那么在给定C#中CompareTo的方式的情况下,结果会有一些差异。因此,执行断言会导致一些令人困惑的结果,不应该用作检测序列结果的方法。

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

你可以这样做:

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