我有一个集合,我只需要按整个数组查找文档;我想不出我只想通过该数组的一个值来查找文档的任何场景。不幸的是,始终为数组值激活的多键功能显然无法停用。
在文档中它说“索引将用于查找值的子集(当前是第一个),然后将检查文档是否完全匹配。” 我认为这大大降低了我的表现。尽管有索引,但有些查找需要 70 毫秒和几分钟,因为根据第一个元素,MongoDB 有时必须搜索几千或几十万个文档。至少这是我的理论。
有没有办法避免这个问题,或者我应该序列化我的数组并将它们存储为字符串?
提前致谢!
也许您可以使用如下子文档:
{
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,
...
*/