We are using MongoDB as primary DB at VersionEye, together with MongoID. Software package is a document in the “products” collection. These products collections has a subcollection with “versions”. Assume we want to know how many versions/artifacts existed for a given language to a given time?
That is not a simple query in MongoDB. This kind of queries can be handled with Map & Reduce. With Map & Reduce you can execute JavaScript on DB Level. Here is the current solution:
border = until_date.at_midnight + 1.day map = %Q{ function() { if ( this.versions == null || this.versions.count == 0 ) return; that_day = new ISODate("#{border.iso8601}"); for (var version in this.versions){ created = this.versions[version].created_at if (created != null && created.getTime() < that_day.getTime()){ emit( this.versions[version]._id, { count: 1 } ); } } } } reduce = %Q{ function(key, values) { var result = { count: 0 }; values.forEach(function(value) { result.count += value.count; }); return result; } } Product.where(:language => language, :created_at.lt => border ).map_reduce(map, reduce).out(inline: true)
The tricky part was this line:
that_day = new ISODate("#{border.iso8601}");
To find out how to convert a Ruby Date object into the JavaScript Date object.
Otherwise you have to know that even through you are iterating over a versions collection you can not access the version object through “version”! You have to access it this way:
this.versions[version]
Otherwise it works fine 🙂