I started working with MongoDB a few days ago. To oversimplify, think of Mongo as a really big and fast hash that gets saved to disk. It lets you query, retrieve, and manipulate data in Javascript and JSON. I had a ton of work to do, so I didn't get a chance to explore the technology as much as I would've liked. Today, after getting a solid night's sleep, I got a chance to experiment more. Read on to get some quick tips about writing Mongo queries and generating reports from the Mongo shell.
When I first started interacting with Mongo, I used the Ruby Mongoid adapter. It gave me a familiar ActiveRecord interface so I could accomplish things like:
Beer.all(:conditions => { :style => "stout" })
But it also gave me a sneak peak at Mongo's 'criteria' API for querying
Beer.criteria.where(:style => "stout")
It's worthwhile to note that criterias are lazily loaded, meaning that the query isn't performed until you actually need to access the data.
Beer.criteria.where(:style => "stout") # doesn't hit mongo
Beer.criteria.where(:style => "stout").first.drink! # executes actual query
This was all fine and dandy, but just like learning SQL and ActiveRecord, having an understanding of the underlying system gives you a better idea of what you can do. So I busted out the mongo shell and started running queries. The tutorial was a good starting point for familiarizing myself with how to connect to mongo, executing some queries, and printing out results. My favorite feature was that the mongo shell doubled as a Javascript interpreter. I was able to write JS to manipulate the query results:
function map(arr, func) {
var collection = [];
if(arr && arr.length) {
for(var i = 0; i < arr.length; i++) {
collection.push(func(arr[i]));
}
}
return collection;
}
db.beers.find().forEach(function(beer) {
print(beer.name);
print('--------------');
map(beer.ingredients, function(ingredient) {
print(beer.ingredient.quantity + ' - ' + beer.ingredient.name);
});
});
I got pretty tired of copying and pasting this script every time I edited it. Thankfully, mongo shell lets you pass in script files to execute:
> mongo --help
MongoDB shell version: 1.4.0
usage: mongo [options] [db address] [file names (ending in .js)
This little feature enabled me to write more complex scripts and tweak to my heart's content. Something was still missing though. I love Javascript as a language, but nowadays, I've grown so accustomed to jQuery that I'll start typing jQuery assuming it's available even when it's not.
db.beers.find().forEach(function(beer) {
// CURSES! JQuery isn't available :(
$(beer.ingredients).each(function() {
// ... do something
});
})
My next genius idea: load jQuery as the first script:
> mongo beerdb jquery-1.4.2.min.js reporting.js
JS Error: ReferenceError: window is not defined jquery-1.4.2.min.js:153
failed to load: jquery-1.4.2.min.js
Noooooo! It makes a lot of sense that jQuery would assume a browser environment, but I was hoping that it wouldn't require it for the nice utility functions.
To get the job done, I wrote myself a small utility library:
$ = {
// > $.map([1,2,3,4], function(x) { return x*x; }
// [1,4,9,16]
map: function(arr, func) {
var collection = [];
if(arr && arr.length) {
for(var i=0; i<arr.length; i++) {
collection.push(func(arr[i]));
}
}
return collection;
},
// > $.max([1,2,3,4])
// 4
// > $.max([1,2,3,4], function(x) { return x*2; })
// 8
max: function(arr, func) {
if(arr == undefined) { return arr; }
var max = null;
for(var i=0; i<arr.length; i++) {
var current = (func ? func(arr[i]) : arr[i]);
max = (current > max ? current : max);
}
return max;
},
}
This didn't buy me the full power of JQuery, but at the same time, I was pretty happy I was able to quickly whip together some JS and get the reports I needed.
Does anyone know of a JS library that buys you a lot of core library features and fixes, but doesn't assume a browser? I looked at John Resig's Env.js, but even that assumes that you're running JS in Rhino. What other Mongo tricks do people find useful?
Here's the order I recommend reading the Mongo documentation. The Advanced Queries link was especially useful.
All databases are fictional. No beers were harmed in the making of this blog post.