Drew
Drew

Reputation: 127

MongoDB Map Reduce on object fields

With documents like:

{
    _id: 123,
    events: {
        someEvent:{
            created: ISODate("2015-06-27T16:51:03.000Z"),
            metadata: {
                some: "thing"
            }
        },
        anotherEvent:{
            created: ISODate("2015-06-27T16:51:01.000Z"),
            metadata: {
                some: "thing"
            }
        }
    }
}

This is a simplified example of the data. The events object can have between 200 and 3,000 fields. There are thousands of documents like this.

I'm looking to use mapreduce on the collection so I only return one of the events (the one with the latest 'created' date) for each document in the collection.

Is this possible?

Upvotes: 1

Views: 844

Answers (1)

Blakes Seven
Blakes Seven

Reputation: 50426

Yes it's possible. MapReduce is a bit of a "blunt edged sword" for this, but your element structure is "not great" and a possible 3000 elements needs something like this:

db.collection.mapReduce(
    function() {
        var doc = this;
        var plucked = Object.keys(doc.events)
            .map(function(key) { 
                var myObj = doc.events[key];
                myObj.key = key;
                return myObj;
            })
            .sort(function(a,b) { 
                return ( a.created > b.created ) 
                    ? -1 : ( a.created < b.created ) 
                    ? 1 : 0; 
            })[0];

        emit(this._id, plucked);
    },
    function() {},
    { "out": { "inline": 1 } }
);

So basically that cylces though "events" and reshapes the data somewhat. Then you .sort() on the "created" key of the results in "descencing order" and just pull the first array element.

The "reducer" does nothing here. But this is just a way for the server to do the filtering.

Upvotes: 2

Related Questions