3

我有一个集合,我只需要按整个数组查找文档;我想不出我只想通过该数组的一个值来查找文档的任何场景。不幸的是,始终为数组值激活的多键功能显然无法停用。

文档中它说“索引将用于查找值的子集(当前是第一个),然后将检查文档是否完全匹配。” 我认为这大大降低了我的表现。尽管有索引,但有些查找需要 70 毫秒和几分钟,因为根据第一个元素,MongoDB 有时必须搜索几千或几十万个文档。至少这是我的理论。

有没有办法避免这个问题,或者我应该序列化我的数组并将它们存储为字符串?

提前致谢!

4

1 回答 1

1

也许您可以使用如下子文档:

{
  array_sub_doc: { arr: [1,2,3,4,5] }
}

这样您就可以进行以下匹配:

db.coll.ensureIndex({array_sub_doc:1});
db.coll.find({array_sub_doc: {arr:[1,2,3,4,5]}})

更新我发现了导致大型阵列失败的原因。> 800 字节的索引键将不会被索引。所以,如果你有一个很大的子文档并且你在上面放了一个索引,如果它大于 800 字节,你尝试搜索它,你不会找到它。如果您关闭索引并再次搜索相同的子文档,您会找到它(尽管这将是一个完整的集合扫描)。

这在此处记录为限制,并将在未来的版本中删除:https ://jira.mongodb.org/browse/SERVER-3372

因此,这通常适用于小型阵列。

如果有人想尝试一下,这里有一些测试代码:

var randomArray = function() {
  var len = 80;
  var randomarr = new Array();
  for (var i=0; i<len; i++) {
    randomarr.push(Math.floor(Math.random() *10000));
  }
  return randomarr;
}

var insert = function() {
  db.Test2.ensureIndex({array_sub_doc:1});
  for(var i=0;i<10000;i++) {
    db.Test2.save({array_sub_doc: {arr: randomArray()}});
  }
}

db.Test2.remove();
insert();

var one = db.Test2.findOne();
db.Test2.findOne({array_sub_doc:one.array_sub_doc});

//...

db.Test2.find({array_sub_doc:one.array_sub_doc}).explain(0);
/* outputs:
{
  "cursor" : "BtreeCursor array_sub_doc_1",
  "nscanned" : 1,
  "nscannedObjects" : 1,
  ...
*/
于 2012-01-18T17:59:25.653 回答