February 23, 2010

Array Keys Allow For Modeling Simplicity

To silence the critics before they start, I will divulge that this feature could have been added with any database. Gasp! What I love is how easy Mongo made it.

For a few weeks now, we have been wanting to add some kind asset integration on the content edit form. I wanted any asset to be linkable to any item (items are pages, blogs, etc.).

Thinking Relationally

Given that Harmony was powered by a relational database, say MySQL, I would have created a new join table, probably related_assets. It would have a column for the asset_id and the item_id (and probably an incrementing id). Then, I would have created a model for this (RelatedAsset).

I would have migrated, prepped my test database, tested the model and added all the relationships like Item has_many :related_assets and has_many :assets, :through => :related_assets (and also reciprocal relationships on the Asset model.

At this point I would be several lines of code and test code in. Also, I would have to block my database for a bit while migrating in production, etc, etc. Lets switch over to awesome and see how I actually did it with Mongo.

Throw Off Them There Shackles

Knowing that the majority of the time I would be wanting to get the assets for an item (instead of the items for an asset), I added an asset_ids Array key on Item. Using MongoMapper, I can then declare my assets association to work through that key like this (more on in array association):

No join model needed. No migrations or prepping my test database. I simply added a key to store some related information and I was good to go. The only other piece I did was add an after_destroy callback to asset to pull itself out of all the item asset_ids keys.

pull is a class method that MongoMapper adds to apply the Mongo $pull operator which you can read more about on their site.

Querying in Array Keys

Really for our purposes here, there was no need to index the asset_ids key as I am not querying by it at all. The reason I did is because eventually, we are going to show what items an asset is being used on from the assets area. This means we will need to query for an asset from the Item asset_ids key, so indexing is important. An example of how to do this would be:

These examples would use the index on asset_ids to efficiently find all items that an asset has been linked to.

Less Code, Less Friction

The fact that we wrote most of Harmony using MySQL and then switched to Mongo makes me feel pretty confident that this feature would have been at least twice, maybe three times as much code. It might have been enough more of a pain, that we would have waited longer to do it, or even worse, wrote it off.

@Jeremy: I think the first pair is probably the find predicate (i.e. find items that have a particular ID in their asset_ids array) and the second pair is what to pull (i.e. remove the specified ID from the asset_ids array).

I’m new to Rails and MongoDB and Linux and all this fun stuff. Do Rails peeps have in depth discussions about singular vs plural naming conventions for tables, collections etc. ?