Tuesday, January 24, 2012

MongoDB Tip #2 - updating fields via Java/Groovy (Bicycle Shop Example)


First post of the new year, 2nd MongoDB tip... here we go!

Let's say that you're writing software for a bicycle repair shop. You need to update the "flat tire" status for a handful of customers because those tires were repaired by the repair shop team.

Using native MongoDB Javascript, you might craft the following:

db.bicycleJobs.update({jobId : { $in: [ 110234, 110433, 110511, 110766] }}, 
 {$set : {flatTire:false}}, false, true); 

Yes, we could cruft up a javascript file to do this, but you want to grab the customer job numbers (e.g., 110234 above) from a file or your inventory system.
So you decide it would be much more convenient to do it in Java or Groovy. Interrogating the native mongo statement we used above, you can probably guess what the update method signature looks like according to the Java Driver for MongoDB.

customers.update(document1, document2, flag1, flag2)
document1
This is our "select" that identifies the target rows based on job numbers in the provided list.
document2
This is our "action" document that actually states the operation to take place. Here we "set" the field called "flatTire" to false.
flag1
This is the "multi" flag. It indicates that the set operation should be applied to all rows that match the results of document1, not just the first match, which would be the default behavior. Having been burned in the past, that's what I call a nice default behavior!
flag2
This is an "upsert" indicator, meaning if there's no match to be had according to document1, then create the row, initialized with these two fields: jobId and flatTire. Might look good on the books, but let's keep this behavior turned off since it probably reveals a data entry error (with respect to the correct jobId).

So a more useful description of this Groovy method signature might something like:

bicycleJobs.update(findDoc, operationDoc, multiFlag, upsertFlag)

Now here's some code to tie things together...


def jobList = [] as BasicDBList

jobList << 110234 // until we're reading from a file or other data source...
jobList << 110433
jobList << 110511
jobList << 110766

def findDoc = new BasicDBObject().append('jobId', 
 new BasicDBObject().append('$in', jobList ));

if (verbose) {  // This bit gives us a little debug to see "the before"...
 def cur = leads.find(findDoc)
 while (cur.hasNext()) {
  def customerRow = cur.next()
  println customerRow['jobId'] + ': flatTire: ' + 
   customerRow['flatTire']  + ': customer: ' + 
   customerRow['name']
 }
}

def operationDoc = new BasicDBObject().append('$set', 
 new BasicDBObject().append('flatTire', false));

def multiFlag = true // update all matches
def upsertFlag = false

db.bicycleJobs.update(findDoc, operationsDoc, multiFlag, upsertFlag)

//You could repeat the "verbose" block above to confirm the expected results.

That's it for now. As I build my knowledge with native mongoDB, I'm trying to make sure I know how to do the equivalent in Java/Groovy. Once you understand how to use Hashes and BasicDBOObject operations to build a document, then it appears to be pretty straightforward.






No comments:

Post a Comment

I turned on comments to see how it goes...