4. 掌握查找

第一章对find命令作了一些简单的介绍,除了选择器以外,find还有很多其他的特性。之前有提到过find返回的结果是一个游标。现在就将对这点做深入的讨论。

域的选择

在开始游标的话题之前,您需要知道find还有第二个可选参数。该参数是一个列表,用户在这个表中指明要求find读取的域。例如,可以用下面的命令获取所有独角兽的名字:

db.unicorns.find(null, {name: 1});

_id域在默认情况下总是会被find返回的。{name:1, _id: 0}可以显式地从返回结果中排除它。

除了上面排除_id域的情况外,不可以将选择与排除的表达式混在一起使用(译者:比如说{_id:1, name:0}或者{name:1, gender:0}都是不合法的)。想一想其实也合乎逻辑:不是显式地选择,就是说明哪些域需要排除。

排序

我已经好几次提到,find返回的是一个游标,对游标的操作直到必要的时候才会执行。然而在shell中的感觉却是find马上就执行了。这仅仅是find在shell中的行为。我们可以通过把find和一个命令连接起来的方法观察find真正的行为。我们先用sort来做这个实验。sort的运作方式有点像上一节提到的域的选择:标明哪些域需要排序,用1表示升序,用-1表示降序。例如:

//最重的独角兽排在第一
db.unicorns.find().sort({weight: -1})

//优先按名字排序再按吸血技能排序
db.unicorns.find().sort({name: 1, vampires: -1})

如同关系数据库,MongoDB也可以利用索引进行排序。我们会在后面再详细讨论索引。只是您要知道,当没有建立索引时,MongoDB是限制排序对象大小的(译者:目前是16MB)。也就是说,如果您尝试对一个大规模的结果的集进行排序,而又没有为这个结果建立索引,那么就会看到错误的提示。对一些人来说,这是MongoDB的局限性。但是说实话,我真希望更多的数据库能够像MongoDB那样拒绝执行那些未经优化的查询。(我倒不是要把每个MongoDB的缺点都硬掰成优点,只是我见过太多缺乏优化的数据库了,所以我真的很希望它们能有一个严格模式以限制未经优化的查询。)

分页(paging)

对结果的分页可以通过limit以及skip这两个游标操作来实现。比如可以用以下的命令来得到第二,第三重的独角兽:

db.unicorns.find().sort({weight: -1}).limit(2).skip(1)

对非索引域进行排序是很麻烦的,联合limit一起使用sort是避免此类麻烦的好方法。

计数

在shell中我们可以对一个集合直接地执行count命令,例如:

db.unicorns.count({vampires: {$gt: 50}})

而现实中count却是一个游标的操作,shell只是提供了一条捷径而已。在使用没有提供这些捷径的驱动时,就要用到下面的命令(在shell中也有用):

db.unicorns.find({vampires: {$gt: 50}}).count()

本章小结

findcursors的使用是比较直接明了的。还有一些额外的命令,有一些会在后面的章节继续介绍,其他的几乎都只是用在很少见的情况了。到现在为止您应该可以比较自如的在mongo的shell工作,也了解了MongoDB的基础知识了。