• No results found

117MongoDB’s query language

In document Mongodb in Action (Page 142-146)

Constructing queries

117MongoDB’s query language

Finally, the symbol type has no representation. That’s because in most languages it’s not used—it’s only used where the language has a distinct type for “keys.” For instance, in Ruby there’s a difference between "foo" and :foo—the latter is a symbol.

The Ruby driver will store any key as a symbol.

5.2.2 Query options

All queries require a query selector. Even if empty, the query selector essentially defines the query. But when issuing a query, you have a variety of query options to choose from that allow you to further constrain the result set. Let’s look at those options next.

PROJECTIONS

You can use a projection to select a subset of fields to return from each document in a query result set. Especially in cases where you have large documents, using a projec-tion will minimize the costs of network latency and deserializaprojec-tion. The only operator,

$slice, is summarized here:

$slice Select a subset of a document to be returned Projections are most commonly defined as a set of fields to return:

db.users.find({}, {'username': 1})

This query returns user documents excluding all but two fields: the username and the _id field, which is a special case and always included by default.

In some situations you may want to specify fields to exclude instead. For instance, this book’s user document contains shipping addresses and payment methods, but you don’t usually need these. To exclude them, add those fields to the projection with a value of 0:

db.users.find({}, {'addresses': 0, 'payment_methods': 0})

In your projection you should either do inclusions or exclusions, though the _id field is a special case. You can exclude the _id field in the same way, by setting the value to 0 in the projection document.

In addition to including and excluding fields, you can return a range of values stored in an array. For example, you might want to store product reviews within the

BSON symbol types

As far as querying is concerned, the MongoDB server will treat a BSON symbol type in the same way it treats a string; it’s only when the document is retrieved that a dis-tinct symbol type mapping to the language key type is done. Note also that the sym-bol type is deprecated in the latest BSON spec (http://bsonspec.org) and may disappear at any moment. Regardless of the language you write your data with, you’ll be able to retrieve it in any other language with a BSON implementation.

118 CHAPTER 5 Constructing queries

product document itself. In this case, you’d still want to be able to paginate those reviews, and for that you could use the $slice operator. To return the first 12 reviews, or the last 5, you’d use $slice like this:

db.products.find({}, {'reviews': {$slice: 12}}) db.products.find({}, {'reviews': {$slice: -5}})

$slice can also take a two-element array the values of which represent numbers to skip and limit, respectively. Here’s how to skip the first 24 reviews and limit the num-ber of reviews to 12:

db.products.find({}, {'reviews': {$slice: [24, 12]}})

Finally, note that using $slice won’t prevent other fields from being returned. If you want to limit the other fields in the document, you must do so explicitly. For example, here’s how you can modify the previous query to return only the reviews and the review rating :

db.products.find({}, {'reviews': {'$slice': [24, 12]}, 'reviews.rating': 1})

SORTING

As we touched on early in this chapter, you can sort any query result by one or more fields in ascending or descending order. A simple sort of reviews by rating, descending from highest to lowest, looks like this:

db.reviews.find({}).sort({'rating': -1})

Naturally, it might be more useful to sort by helpfulness and then by rating:

db.reviews.find({}).sort({'helpful_votes':-1, 'rating': -1})

In compound sorts like this, the order does matter. As noted elsewhere, JSON entered via the shell is ordered. Because Ruby hashes aren’t ordered, you indicate sort order in Ruby with an array of arrays, which is ordered:

@reviews.find({}).sort([['helpful_votes', -1], ['rating', -1]])

The way you specify sorts in MongoDB is straightforward; understanding how indices can help improve sorting speeds is critical to using them well. We’ll get to that in chap-ter 8, but feel free to skip ahead if you’re using sorts heavily now.

SKIPANDLIMIT

There’s nothing mysterious about the semantics of skip and limit. These query options should always work as you expect. But you should beware of passing large val-ues (say, valval-ues greater than 10,000) for skip because serving such queries requires scanning over a number of documents equal to the skip value. For example, imagine you’re paginating a million documents sorted by date, descending, with 10 results per page. This means that the query to display the 50,000th page will include a skip value

119 Summary

of 500,000, which is incredibly inefficient. A better strategy is to omit the skip alto-gether and instead add a range condition to the query that indicates where the next result set begins. Thus, this query

db.docs.find({}).skip(500000).limit(10).sort({date: -1})

becomes this:

previous_page_date = new Date(2013, 05, 05)

db.docs.find({'date': {'$gt': previous_page_date}}).limit(10).sort({'date': -1})

This second query will scan far fewer items than the first. The only potential problem is that if date isn’t unique for each document, the same document may be displayed more than once. There are many strategies for dealing with this, but the solutions are left as exercises for the reader.

There’s another set of query types that you can perform on MongoDB data: geo-spatial queries, which are used to index and retrieve geographical or geometric data and are typically used for mapping and location-aware applications.

5.3 Summary

Queries make up a critical corner of the MongoDB interface. Once you’ve skimmed this chapter’s material, you’re encouraged to put the query mechanisms to the test. If you’re ever unsure of how a particular combination of query operators will serve you, the shell is always a ready test bed.

MongoDB also supports query modifiers that are meta-operators that let you modify the output or behavior of a query. You can find more about them at http://

docs.mongodb.org/manual/reference/operator/query-modifier/.

You’ll use MongoDB queries consistently from now on, and the next two chapters are a good reminder of that. You’ll tackle aggregation, document updates, and deletes. Because queries play a key role in most updates, you can look forward to yet more exploration of the query language.

120

Aggregation

In the previous chapter, you saw how to use MongoDB’s JSON-like query language to perform common query operations, such as lookup by ID, lookup by name, and sorting. In this chapter, we’ll extend that topic to include more complex queries using the MongoDB aggregation framework. The aggregation framework is MongoDB’s advanced query language, and it allows you to transform and combine data from multiple documents to generate new information not available in any single docu-ment. For example, you might use the aggregation framework to determine sales by month, sales by product, or order totals by user. For those familiar with relational databases, you can think of the aggregation framework as MongoDB’s equivalent to the SQL GROUP BY clause. Although you could have calculated this information pre-viously using MongoDB’s map reduce capabilities or within program code, the aggregation framework makes this task much easier as well as more efficient by

This chapter covers

Aggregation on the e-commerce data model

Aggregation framework details

Performance and limitations

Other aggregation capabilities

121

In document Mongodb in Action (Page 142-146)

Related documents