Lecture
In Chapter 1 we briefly covered the find command. However, find is not just about selectors. As already mentioned, the result of find is a cursor. It's time to look at this in more detail.
Before we move on to cursors, you should know that find accepts a second, optional parameter. This is a list of the fields we want to get back. For example, we can get the names of all unicorns with the following query:
db.unicorns.find(null, {name: 1});
The _id field is always returned by default. We can explicitly exclude it by specifying {name:1, _id: 0}.
With the exception of the _id field, you cannot mix field inclusions and exclusions. If you think about it, you can understand why it's done this way. You can either want to include fields, or conversely want to explicitly exclude certain fields.
I've already mentioned a few times that find returns a cursor, which executes lazily - only as needed. However, you've no doubt already seen that find executes immediately. This behavior is specific to the console. You can observe the true behavior of cursors by looking at any of the methods we can chain onto find. The first of these is sort. The syntax of sort is roughly the same as the field selection we saw in the previous section. We specify the fields to sort by, using 1 for ascending order and -1 for descending order. For example:
//sort by weight - from heaviest to lightest unicorns
db.unicorns.find().sort({weight: -1})
//by unicorn name, then by number of vampires killed:
db.unicorns.find().sort({name: 1, vampires: -1})
Like a relational database, MongoDB can use indexes for sorting. We'll look at indexes in more detail a bit later. However, you should know that without an index, MongoDB limits the size of the data it can sort. If you try to sort a large amount of data without using an index, you'll get an error. Some consider this a limitation. Although I think it wouldn't hurt other databases to forbid the execution of non-optimal queries either. (I'm not going to turn every shortcoming of MongoDB into a virtue, but I've come across plenty of non-optimal databases that badly needed this kind of strict-checking mode.)
Pagination can be done using the limit and skip methods. To get the second and third heaviest unicorn, you can run:
db.unicorns.find().sort({weight: -1}).limit(2).skip(1)
Using limit together with sort lets you avoid problems with sorting on unindexed fields.
The console lets you run count directly on a collection:
db.unicorns.count({vampires: {$gt: 50}})
In practice, though, count is a cursor method - the console just provides a convenient shortcut. With drivers that don't support this kind of shortcut, you need to write something like this (of course, you can do it this way in the console too):
db.unicorns.find({vampires: {$gt: 50}}).count()
It's quite simple to work with find and cursors. There are a few more additional commands that we'll either cover later or not cover at all (since they only apply in edge cases), but by now, I think, you should already be comfortable working with the mongo console and understanding the core principles of MongoDB.
Comments