2013-04-04 65 views
0

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

这是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比较算法?

+0

当您从MongoDB的壳牌查询的顺序一样吗?我只是想看看这是否是一个司机的问题。 – Majid 2013-04-04 18:57:16

+0

订单与MongoDB Shell的订单相同。 – fparadis2 2013-04-05 12:22:01

+0

我发现了这个问题。 C#驱动程序将ObjectId组件存储为带符号整数,并使用默认的带符号比较。服务器使用ObjectId的无符号表示进行排序。就我而言,我有时会遇到这样的情况:对于同一时间戳/机器,我有一个“正面”和一个“负面”(签名时)的pid。在这种情况下,有符号和无符号比较不会给出相同的结果。我认为这是C#驱动程序中的一个错误。 – fparadis2 2013-04-05 12:23:50

回答

0

MongoDB C#的源代码目前是here。该代码将ObjectId的每个元素与3字节计数器进行比较。给定包含ObjectId的性质:

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

在时间戳之外排序没有意义。 CompareTo虽然准确并且会产生一致的结果,但可能无法以与您的预期相符的方式排序。

鉴于将会出现两个对象在同一时间戳(4字节值)下创建的实例,因此在结果中给出了C#中CompareTo的工作方式。因此,执行断言会导致一些令人困惑的结果,因此不应将其用作检测失序结果的方式。

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

你可以这样做:

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

断言只是一个测试:)。我实际上想要做的是每次处理一堆文件,每次存储“最后处理的_id”,之后我可以从其中恢复(在另一次运行中)。这要求从服务器进行排序是可靠的。希望这种排序至少与$ gt运算符一致,所以我可以使用排序查询返回的最后一个文档的_id,然后在下一个查询中使用{$ gt:last_id}。 – fparadis2 2013-04-04 18:06:25

+0

你绝对可以做到这一点。服务器上的排序是一致的。 – 2013-04-05 16:08:01