Windows 7 64 SP1 - MongoDB 2.2.0-rc2 - 提升1.42 - MS VS 2010旗舰版 - C ++驱动程序
关注“Mongo in Action”,在shell中:
for(i=0; i<200000; i++){
db.numbers.save({num: i});
}
db.numbers.find()显示:
{ "_id": ObjectId("4bfbf132dba1aa7c30ac830a"),"num" : 0 }
{ "_id": ObjectId("4bfbf132dba1aa7c30ac830b"),"num" : 1 }
{ "_id": ObjectId("4bfbf132dba1aa7c30ac830c"),"num" : 2 }
{ "_id": ObjectId("4bfbf132dba1aa7c30ac830d"),"num" : 3 }
...
所以,用C ++复制:
// Insert 200,000 documents
for ( int i = 0; i < 200000 ; i++)
c.insert(dc,BSON(GENOID << "num" << i));
//Display the first 20 documents
Query qu = BSONObj();
auto_ptr<DBClientCursor> cursor = c.query(dc,qu);
for ( int i = 0 ; i < 20 ; i++){
cout << cursor->next().toString() << endl;
}
输出:
{ "_id" : ObjectId("504bab737ed339cef0e26829"), "num" : 199924 }
{ "_id" : ObjectId("504bab737ed339cef0e2682a"), "num" : 199925 }
{ "_id" : ObjectId("504bab737ed339cef0e2682b"), "num" : 199926 }
{ "_id" : ObjectId("504bab737ed339cef0e2682c"), "num" : 199927 }
....
在shell中调用db.numbers.find()具有相同的输出。为什么不以{“num”:0}开头?它存在:
> db.numbers.find({"num" : 0})
{ "_id" : ObjectId("504bab417ed339cef0df5b35"), "num" : 0 }
{“num”:0}的_id位于{“num”:199924}的_id之前
“_id”的索引存在:
> db.numbers.getIndexes()
[
{
"v" : 1,
"key" : {
"_id" : 1
},
"ns" : "learning.numbers",
"name" : "_id_"
}
]
如果我通过将查询代码更改为_id来添加_id排序:
auto_ptr<DBClientCursor> cursor = c.query(dc,qu.sort("_id"));
然后按顺序打印:
{ "_id": ObjectId("4bfbf132dba1aa7c30ac830a"),"num" : 0 }
{ "_id": ObjectId("4bfbf132dba1aa7c30ac830b"),"num" : 1 }
...
对于较小的文档集合(例如200个),不会发生这种情况。
问题:为什么看起来C ++查询没有在_id上使用集合的索引?或者还有什么可以解释这种明显的异常(或者我缺乏理解?
答案 0 :(得分:2)
索引和排序是不同的概念。您可以在索引中查找数据而无需对结果进行排序;您也可以在不使用索引的情况下对结果进行排序(尽管不建议这样做)。
由于您尚未为find()
指定排序顺序,因此结果将在natural order中返回。对于只插入文档(并且从不删除或更新)的集合,自然顺序应该近似于插入顺序(除非您碰巧使用capped collection,这是按插入顺序维护的。)
一旦你开始删除文件或更新它们(这可能会导致它们被移动),MongoDB的preallocated data files中就会产生可用空间“空白”。 MongoDB将重用可用空间用于新文档插入/移动..因此,随着时间的推移,自然顺序将不再与插入顺序匹配。
如果您希望按特定排序顺序排列结果,则必须在查询中包含此结果。
答案 1 :(得分:0)
@stenni谢谢 - 这些“差距”是问题,并引导我找到解决方案。在查询时,shell中的自然顺序似乎比C ++驱动程序更“自然”,后者以非常大的“num”开头。但是,错误在于我的方法论:
db.numbers.find()
;列出的第一份文件是{"num" : 0}
db.numbers.remove()
db.numbers.find()
;列出的第一份文件是{"num" : SomeVeryLargeNumber}
相反,我应该使用db.numbers.drop()
,实际上删除了该集合。这样做意味着第5步列出的第一个文档是{"num" : 0}
。 db.numbers.remove
显然可以保持差距。