3

Windows 7 64 SP1 -- MongoDB 2.2.0-rc2 -- Boost 1.42 -- MS VS 2010 Ultimate -- 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排序:

auto_ptr<DBClientCursor> cursor = c.query(dc,qu.sort("_id")); 

然后它按顺序打印:

{ "_id": ObjectId("4bfbf132dba1aa7c30ac830a"),"num" : 0 }
{ "_id": ObjectId("4bfbf132dba1aa7c30ac830b"),"num" : 1 }
...

较小的文档集合(例如 200 个)不会发生这种情况。

问题:为什么 C++ 查询似乎没有使用 _id 上的集合索引?或者还有什么可以解释这种明显的异常(或我缺乏理解?

4

2 回答 2

2

索引和排序是不同的概念。您可以在索引中查找数据而无需对结果进行排序;您也可以在不使用索引的情况下对结果进行排序(尽管不推荐这样做)。

由于您没有为您find()的 指定排序顺序,结果将按自然顺序返回。对于仅插入文档(并且从未删除或更新)的集合,自然顺序应该近似于插入顺序(除非您碰巧使用了按插入顺序维护的封顶集合)。

一旦您开始删除或更新文档(这可能会导致它们被移动),MongoDB 的预分配数据文件中就会产生可用空间“间隙” 。MongoDB 将重新使用可用空间进行新文档的插入/移动 .. 所以随着时间的推移,自然顺序将不再与插入顺序匹配。

如果您希望得到特定排序顺序的结果,则必须将其包含在查询中。

于 2012-09-08T23:04:37.207 回答
0

@stenni 谢谢——那些“差距”是问题所在,并引导我找到了解决方案。查询时,shell 中的自然顺序似乎比 C++ 驱动程序更“自然”,后者以非常大的“num”开头。但是,错误在于我的方法:

  1. 在 shell 中插入 200000 个文档。
  2. db.numbers.find(); 列出的第一个文件是{"num" : 0}
  3. db.numbers.remove()
  4. 使用 C++ 驱动插入 200000 个文档
  5. db.numbers.find(); 列出的第一个文件是{"num" : SomeVeryLargeNumber}

相反,我应该使用db.numbers.drop(),实际上删除了集合。这样做意味着第 5 步列出的第一个文档是{"num" : 0}. db.numbers.remove显然保持了差距。

于 2012-09-09T05:31:25.987 回答