Javascript MongoDB:发现({…})背后的真相。限制(#)
在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()方法“返回文档”时,该方法实际上是向文档返回一个光标 当您迭代光标时,文档实
.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”对象的概念(因此我确信,如果有任何价值可以等待,那么只有承诺实例的价值会在这个过程中发生变化)。