2013-04-04 81 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