Database Reference
In-Depth Information
But now what if you update a category name? If you change the name of Outdoors to
The Great Outdoors, then you also have to change Outdoors wherever it appears in
the ancestor lists of other categories. You may be justified in thinking, “See? This is
where denormalization comes to bite you,” but it should make you feel better to know
that you can perform this update without recalculating any ancestor list. Here's how:
doc = @categories.find_one({:_id => outdoors_id})
doc['name'] = "The Great Outdoors"
@categories.update({:_id => outdoors_id}, doc)
@categories.update({'ancestors.id' => outdoors_id},
{'$set' => {'ancestors.$'=> doc}}, :multi => true)
You first grab the Outdoors document, alter the name attribute locally, and then
update via replacement. Now you use the updated Outdoors document to replace its
occurrences in the various ancestor lists. You accomplish this using the positional
operator and a multi-update. The multi-update is easy to understand; recall that you
need to specify :multi => true if you want the update to affect all documents match-
ing the selector. Here, you want to update each category that has the Outdoors cate-
gory in its ancestor list.
The positional operator is more subtle. Consider that you have no way of knowing
where in a given category's ancestor list the Outdoors category will appear. You thus
need a way for the update operator to dynamically target the position of the Outdoors
category in the array for any document. Enter the positional operator. This operator,
here the $ in ancestors.$ , substitutes the array index matched by the query selector
with itself, and thus enables the update.
Because of the need to update individual sub-documents within arrays, you'll
always want to keep the positional operator at hand. In general, these techniques for
updating the category hierarchy will be applicable whenever you're dealing with
arrays of sub-documents.
6.2.2
Reviews
Not all reviews are created equal, which is why this application allows users to vote on
them. These votes are elementary; they indicate that the given review is helpful.
You've modeled reviews so that they cache the total number of helpful votes and keep
a list of each voter's ID . The relevant section of each review document looks like this:
{helpful_votes: 3,
voter_ids: [ ObjectId("4c4b1476238d3b4dd5000041"),
ObjectId("7a4f0376238d3b4dd5000003"),
ObjectId("92c21476238d3b4dd5000032")
]}
You can record user votes using targeted updates. The strategy is to use the $push
operator to add the voter's ID to the list and the $inc operator to increment the total
number of votes, both in the same update operation:
db.reviews.update({_id: ObjectId("4c4b1476238d3b4dd5000041")},
{$push: {voter_ids: ObjectId("4c4b1476238d3b4dd5000001")},
Search WWH ::




Custom Search