Javascript MongoDB:发现({…})背后的真相。限制(#)

Javascript MongoDB:发现({…})背后的真相。限制(#),javascript,node.js,mongodb,mongoose,database,Javascript,Node.js,Mongodb,Mongoose,Database,在MongoDB中,.find({…}).limit(#)真的限制了查询的数量吗 我的意思是,当您执行db.collection.find(condition)时,查询与给定条件匹配的所有结果是否已经浪费了计算能力?如果是这样,那么在它之后添加.limit()是否只是从查询结果中去掉不需要的元素 非常感谢你澄清这一点 db.collection.find返回一个数组,而不是结果数组或类似的数组。从文件中: 当find()方法“返回文档”时,该方法实际上是向文档返回一个光标 当您迭代光标时,文档实

在MongoDB中,
.find({…}).limit(#)
真的限制了查询的数量吗

我的意思是,当您执行db.collection.find(condition)时,查询与给定条件匹配的所有结果是否已经浪费了计算能力?如果是这样,那么在它之后添加
.limit()
是否只是从查询结果中去掉不需要的元素


非常感谢你澄清这一点

db.collection.find
返回一个数组,而不是结果数组或类似的数组。从文件中:

find()
方法“返回文档”时,该方法实际上是向文档返回一个
光标

当您迭代光标时,文档实际上就被定位了。因此,调用
.limit
会告诉光标何时表示迭代完成

有关游标的详细信息,请参见此处:

limit()不用于数据的后期筛选。您可以使用explain()解决这个问题。例如,我启动了2个查询1)db.album.find().explain()2)db.album.find().limit(5.explain();以下是结果:

        > db.album.find().explain()
       {
        "cursor" : "BasicCursor",
        "isMultiKey" : false,
        "n" : 1000,
        "nscannedObjects" : 1000,
        "nscanned" : 1000,
        "nscannedObjectsAllPlans" : 1000,
        "nscannedAllPlans" : 1000,
        "scanAndOrder" : false,
        "indexOnly" : false,
        "nYields" : 54,
        "nChunkSkips" : 0,
        "millis" : 12,
        "server" : "delbsinha25125:27017",
       "filterSet" : false
      }

      > db.album.find().limit(5).explain()
        {
         "cursor" : "BasicCursor",
         "isMultiKey" : false,
         "n" : 5,
         "nscannedObjects" : 5,
         "nscanned" : 5,
         "nscannedObjectsAllPlans" : 5,
         "nscannedAllPlans" : 5,
         "scanAndOrder" : false,
         "indexOnly" : false,
         "nYields" : 0,
         "nChunkSkips" : 0,
         "millis" : 0,
          "server" : "delbsinha25125:27017",
         "filterSet" : false
      }
从上面的执行计划中可以看出,具有限制的执行计划只扫描了5个对象


>

大约5天前,我试图回答这个问题,但后来发现了一些有趣的事情,我必须进行实际调查

然而,限制是在排序和查找之后应用的,而不是在
mongod
(MongoDB)服务器本身中迭代这些结果之前应用的,因此这意味着如果正确地执行,您可以使用限制节省大量计算能力@Bipul的答案是一个完美的例子,但它并没有显示MongoDB在这方面的真正局限性

应该注意的是,如果您使用的是最新版本的MongoDB,那么实际上存在一个限制性bug,它会导致扫描etra条目:这是我在尝试回答此问题时实际发现的问题之一

应该注意的是,上面提到的bug只会对inde使用产生有限的影响

现在考虑到@Bipuls answer没有独立用法,这个故事实际上有两个方面,一个是他展示的内容,另一个是如果你添加排序:

> db.rooms.find().sort({d:1}).limit(2).explain()
{
        "clauses" : [
                {
                        "cursor" : "BasicCursor",
                        "isMultiKey" : false,
                        "n" : 2,
                        "nscannedObjects" : 5,
                        "nscanned" : 5,
                        "scanAndOrder" : true,
                        "indexOnly" : false,
                        "nChunkSkips" : 0
                },
                {
                        "cursor" : "BasicCursor",
                        "isMultiKey" : false,
                        "n" : 0,
                        "nscannedObjects" : 0,
                        "nscanned" : 0,
                        "scanAndOrder" : true,
                        "indexOnly" : false,
                        "nChunkSkips" : 0
                }
        ],
        "cursor" : "QueryOptimizerCursor",
        "n" : 2,
        "nscannedObjects" : 5,
        "nscanned" : 5,
        "nscannedObjectsAllPlans" : 5,
        "nscannedAllPlans" : 5,
        "scanAndOrder" : false,
        "nYields" : 0,
        "nChunkSkips" : 0,
        "millis" : 0,
        "server" : "ubuntu:27017",
        "filterSet" : false
}
集合的大小为5,您可以看到排序后应用了限制,这表明集合必须进行完全扫描,并且由于此查询没有索引,因此将进行完全索引扫描,并且您的计算节省只不过是“从外观上看”

现在,如果您添加一个inde,这是不同的,它实际上可以使用inde的顺序来停止完全扫描并仅在您的限制范围内加载,但是,由于上面的错误,它总是会扫描一个以上的索引,但这是一个inde扫描,而不是加载的实际文档(取决于您的查询find()是否被覆盖)


总之,如果使用正确,limit可以阻止MongoDB加载接收文档,不仅可以节省您的工作集,还可以节省IO带宽。如果你能在inde等中正确使用limit,那么我肯定会推荐它。

当然这不是一个好例子,因为nscaned为5的原因是因为它实际上只需要读取5,这是一个特例,如果你有一个更复杂的查询,你会发现nscaned可以改变limitold问题之外的内容,但仍然需要一些澄清!在NodeJS中,什么是“光标”?承诺?应该是,因为可以等待它:
let cursor=User.find().limit(5);让数组=等待光标。但是
光标实例of Promise
返回false!好的,我明白了。因此,Mongo cursor不是承诺,而是提供then()方法的对象。非常清晰。@JosephMerdrignac-您可以
等待
任何值;如果该值不是thenable,则它不会执行任何操作(等待一个异步“勾选”除外)。我不使用MongoDB,但我在中没有看到任何提示游标是可选项的内容。他们有一些返回承诺的方法,但似乎没有
then
方法(不管怎样,使用
node mongodb native
驱动程序)。在JS中你是对的,一切都可以等待,我使用的是mongoose,NodeJS驱动程序,其中查询是带有then()方法的对象。我甚至发现了一些官方文档:我忽略了“thenable”对象的概念(因此我确信,如果有任何价值可以等待,那么只有承诺实例的价值会在这个过程中发生变化)。