Suppose I’m working on a MongoMapper class that looks like this:
class Animal
include MongoMapper::Document
key :type, String, :required => true
key :color, String
key :feet, Integer
end
Now I want to store a bird’s wingspan. Would it be better to add this, even though it’s irrelevant for many documents and feels a bit untidy:
key :wingspan, Float
Or this, even though it’s an indescriptive catch-all that feels like a hack:
key :metadata, Hash
It seems like the :metadata approach (for which there’s precedent in the code I’m inheriting) is almost redundant to the Mongo document as a whole: they’re both intended to be schemaless buckets of key-value pairs.
However, it also seems like adding animal-specific keys is a slippery slope to a pretty ugly model.
Any alternatives (create a Bird subclass)?
MongoMapper doesn’t store keys that are
nil, so if you did definekey :wingspanonly the documents that actually set that key would store it.If you opt not to define the key, you can still set/get it with
my_bird[:wingspan] = 23. (The[]call will actually automatically define a key for you; similarly if a doc comes back from MongoDB with a key that’s not explicitly defined a key will be defined for it and all docs of that class–it’s kind of a bug to define it for the whole class but sincenilkeys aren’t stored it’s not so much of a problem.)If bird has its own behavior as well (it probably does), then a subclass makes sense. For birds and animals I would take this route, since every bird is an animal. MongoDB is much nicer than ActiveRecord for Single Table/Single Collection Inheritance, because you don’t need a billion migrations and your code makes it clear which attributes go with which classes.