Windows 7 64 SP1--MongoDB 2.2.0-rc2--Boost 1.42--MSVS 2010 Ultimate--C驱动程序
在“Mongo in Action”之后,在shell中:
for(i=0; i<200000; i++){
db.numbers.save({num: i});
}
db. number.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. number.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排序,将查询代码更改为:
auto_ptr<DBClientCursor> cursor = c.query(dc,qu.sort("_id"));
然后它按顺序打印:
{ "_id": ObjectId("4bfbf132dba1aa7c30ac830a"),"num" : 0 }
{ "_id": ObjectId("4bfbf132dba1aa7c30ac830b"),"num" : 1 }
...
这不会发生在较小的文档集合(例如200个)中。
问题是:为什么C查询似乎没有在_id上使用集合的索引?或者还有什么可以解释这种明显的异常(或者我缺乏理解?
索引和排序是不同的概念。您可以在索引中查找数据而无需对结果进行排序;您也可以在不使用索引的情况下对结果进行排序(尽管不建议这样做)。
由于您没有为find()
指定排序顺序,因此结果将按自然顺序返回。对于仅插入文档(且从未删除或更新)的集合,自然顺序应近似于插入顺序(除非您碰巧使用的是按插入顺序维护的上限集合)。
一旦你开始删除文档或更新它们(这可能会导致它们被移动),MongoDB的预分配数据文件中就会产生空闲空间“间隙”。MongoDB将重用空闲空间进行新的文档插入/移动…因此随着时间的推移,自然顺序将不再匹配插入顺序。
如果您期待特定排序顺序的结果,则必须将其包含在查询中。
@stenni谢谢——这些“差距”是问题所在,并让我找到了解决方案。查询时,shell中的自然顺序似乎比C驱动程序更“自然”,后者以一个非常大的“num”开头。然而,错误在于我的方法论:
db. number.find()
;列出的第一个文档是{"num":0}
db。数字。删除()
db. number.find()
;列出的第一个文档是{"num":有一些VeryLargeNumber}
相反,我应该使用db. number.drop()
,实际上是删除集合。这样做意味着第5步列出的第一个文档是{"num":0}
。db.numbers.删除
显然保留了空白。