Mongodb按字符串数组排序并使用索引
如何通过一个字符串数组进行排序进行查询,该数组将在其计划中没有Mongodb按字符串数组排序并使用索引,mongodb,Mongodb,如何通过一个字符串数组进行排序进行查询,该数组将在其计划中没有“stage”:“SORT”的情况下执行 我正在使用mongo 3.6 “mycoll”集合包含大约500000个文档,如下所示: { someobject:{ arrayfield:["asd","qwe"] } } { someobject:{ arrayfield:["zxc"] } } 这个问题 db.mycoll.find().sort({ "someobj
“stage”:“SORT”
的情况下执行
我正在使用mongo 3.6“mycoll”集合包含大约500000个文档,如下所示:
{
someobject:{
arrayfield:["asd","qwe"]
}
}
{
someobject:{
arrayfield:["zxc"]
}
}
这个问题
db.mycoll.find().sort({ "someobject.arrayfield": 1 }).skip(125340).limit(20)
产生错误
排序操作使用的内存超过最大33554432字节
我在“someobject.arrayfield”上有和索引,但explain()给了我:
"winningPlan" : {
"stage" : "SKIP",
"skipAmount" : 125340,
"inputStage" : {
"stage" : "SORT",
"sortPattern" : {
"someobject.arrayfield" : 1
},
"limitAmount" : 125360,
"inputStage" : {
"stage" : "SORT_KEY_GENERATOR",
"inputStage" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"someobject.arrayfield" : 1
},
"indexName" : "arrayfield_indexname",
"isMultiKey" : true,
"multiKeyPaths" : {
"someobject.arrayfield" : [
"someobject.arrayfield"
]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"someobject.arrayfield" : [
"[MinKey, MaxKey]"
]
}
}
}
}
}
}
我知道,我可以增加限制,使用“allowdiskusage”或查询的聚合
db.mycoll.find().sort({ "someobject.arrayfield.1": 1 }).skip(125340).limit(20)
索引位于“someobject.arrayfield.1”我有一个潜在的解决方案,这取决于数组中的实际值,以及您是否只需要稳定排序,或者是否需要基于mongodb使用的数组比较逻辑进行排序 如果您不想阅读有关mongodb如何比较阵列的详细信息,请跳到建议的解决方案部分
起初,我很好奇数组字段上的
.sort()
如何对结果排序。它会使用第一个数组值进行比较吗?还是价值观的某种组合
经过一些测试后,看起来mongodb使用数组中的所有值来比较和排序它们。这是我的测试数据(\u id
为简洁起见省略了字段):
如您所见,它不是基于数组的第一个值进行排序,而是使用一些内部逻辑比较整个数组。它如何准确地确定[“rty”、“aaa”]
应该位于[“xcv”、“aaa”、“bcd”]
之前?为什么[“xcv”、“aaa”、“bcd”]
出现在[“aaa”、“xcv”、“bcd”]
之前?或者他们是平等的,并且它使用_id作为平局破坏者?我真的不知道
我认为可能是使用了标准的javascript比较运算符,但情况似乎也并非如此。我为每个数组创建了一个数组,并在其中调用了.sort()
,得到了以下结果:
x.sort()
[ [ 'aaa', 'xcv', 'bcd' ],
[ 'asd', 'qwe' ],
[ 'bnm' ],
[ 'dfg', 'sdf' ],
[ 'qwe' ],
[ 'rty', 'aaa' ],
[ 'xcv', 'aaa', 'bcd' ] ]
这很有意义,因为很明显,元素之间用逗号分隔符连接,然后进行字符串比较
提议的解决办法
mongodb中的数组比较逻辑对我来说是个谜。但是,这打开了一个可能性,您可能不关心mongodb神秘的数组比较逻辑。如果您只需要一个稳定的排序,这样就可以跳过和限制分页,那么我想我有一个解决方案
如果我们在数组的第一个值上创建索引,就像这样(使用background:1
以避免锁定数据库):
然后我们可以对数组中的第一个对象执行查找查询和排序,这将避免排序阶段:
mongos> db.mycoll.find().sort({"someobject.arrayfield.0":1}).explain()
"winningPlan" : {
"stage" : "LIMIT",
"limitAmount" : 1,
"inputStage" : {
"stage" : "SKIP",
"skipAmount" : 1,
"inputStage" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"someobject.arrayfield.0" : 1
},
"indexName" : "someobject.arrayfield.0_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"someobject.arrayfield.0" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"someobject.arrayfield.0" : [
"[MinKey, MaxKey]"
]
}
}
}
}
}
没有更多的分类阶段
这个建议的解决方案基于一个很大的假设,即您愿意接受与原始查询提供的排序顺序不同的排序顺序。我希望这个解决方案能奏效,你们也能以这种方式实施。如果没有,也许其他人可以扩展这个想法。为什么需要跳过
125340
文档?@styvane要获得第6267页大小为20的文档,是否不可能对文档应用过滤器而不是跳过它们?@styvane让我们说“不”。我的目标是从排序结果中根据页面大小和数量获得页面。我在问题中使用了一个filter子句,因为我认为如果可以使用空find()执行此操作,也可以使用复合索引筛选查询。@Vladmamev,你说得对。这在3.4中还可以,但在3.6和4.0中会产生排序。不幸的是,根据mongo jira的问题,这被认为是“按设计工作”。他们甚至在文档中添加了此限制,请参见和中的注释。已提交改进请求:感谢anwser。不幸的是,对我来说没有什么新鲜事,我找到了相同的可能解决方案,我在问题的最后简要地提到了它。哎呀,抱歉重复了一些你已经知道的事情!我唯一的另一个想法是预先计算数组到浮点的排序顺序,并将其存储在另一个字段中。当数组值更改时,您必须保持该字段同步,但随后可以对其执行排序。
db.mycoll.createIndex( { "someobject.arrayfield.0":1 }, {background:1} )
mongos> db.mycoll.find().sort({"someobject.arrayfield.0":1}).explain()
"winningPlan" : {
"stage" : "LIMIT",
"limitAmount" : 1,
"inputStage" : {
"stage" : "SKIP",
"skipAmount" : 1,
"inputStage" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"someobject.arrayfield.0" : 1
},
"indexName" : "someobject.arrayfield.0_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"someobject.arrayfield.0" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"someobject.arrayfield.0" : [
"[MinKey, MaxKey]"
]
}
}
}
}
}