Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mongodb按字符串数组排序并使用索引_Mongodb - Fatal编程技术网

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]"
               ]
            }
         }
      }
   }
}