How to change the structure of MongoDB's map-r

2019-01-25 16:16发布

问题:

When I'm running Map-Reduce on a Mongo database, I usually get results similar to the following:

{ _id: <some-id>, value: { <first-key>: <first-value>, ... } }

Is there a way to omit the value: { ... } part and directly insert the content of value in the result? Basically, I'd like to have a result that looks like the following:

{ _id: <some-id>, <first-key>: <first-value>, ... }

This way I could merge the results back into an existing collection that obeys this format.

I also have an other question regarding Map-Reduce: Is it possible to access another collection from withing a map or reduce function?

回答1:

MapReduce only returns documents of the form {_id:some_id, value:some_value}

"some_value" does not necessarily have to be an embedded document, but in most cases it is to allow multiple variables to be calculated by the Map Reduce function. The documents returned by the Reduce function must be in the same form as they are input, because the Reduce function may be run repeatedly for any given _id value.

For a step-by-step of how Map Reduce works, please see the "Extras" section of the MongoDB Cookbook recipe titled "Finding Max And Min Values with Versioned Documents" http://cookbook.mongodb.org/patterns/finding_max_and_min/ This should provide a better understanding of how Map Reduce works, and why the output must be in the format {_id:some_id, value:some_value}

It is possible to do an incremental Map Reduce, which will merge the results of multiple Map Reduce functions. http://www.mongodb.org/display/DOCS/MapReduce#MapReduce-IncrementalMapreduce

Finally, it is currently not possible to access multiple collections at once with Map Reduce. There is a feature request for this capability, but it is not scheduled to be added to any upcoming versions.
https://jira.mongodb.org/browse/SERVER-970



回答2:

RE: Accessing other collections from within Map/Reduce functions. What you can do is leverage "scope" to push in data needed by m/r during execution. NOTE: scope only accepts a SIMPLE collection of objects here. By simple, I mean no nested documents.

scope = { People : [{ Name : 'bob', Color : 'blue'}, { Name : 'sally', Color: 'orange'}] }

The above scope collection works fine. In a m/r function just refer to 'People' as a global variable and you can iterate through your collection, etc.

scope = { People : [{ Name : 'bob', Color : { Favorite : 'blue'} }, { Name : 'sally', Color : { Favorite : 'orange' } }] }

The above would not work, depending on the driver you're using you'll get a Range Error and told that the maximum call size has been exceeded or something like that. Sticking with simple objects in scope will keep life simple.



回答3:

This worked for me:
Assuming you are emitting this or a variation of it in map, first set this._id = undefined.
Set out mode to merge.

Check my example here