MongoDB MapReduce update in place as

* Basically, I try to arrange objects according to their evaluation over the last hour.

I am trying to generate an hourly sum of votes for objects in my database. Voices are embedded in every object. The object diagram is as follows:

{ _id: ObjectId score: int hourly-score: int <- need to update this value so I can order by it recently-voted: boolean votes: { "4e4634821dff6f103c040000": { <- Key is __toString of voter ObjectId "_id": ObjectId("4e4634821dff6f103c040000"), <- Voter ObjectId "a": 1, <- Vote amount "ca": ISODate("2011-08-16T00:01:34.975Z"), <- Created at MongoDate "ts": 1313452894 <- Created at timestamp }, ... repeat ... } } 

This question is really related to the question that I asked a couple of days ago. The best way to model a voting system in MongoDB

How can I (can I?) Run the MapReduce command to do the following:

  • It is executed only for objects with a recently voted = true OR hourly score> 0.
  • Calculate the amount of votes created in the last hour.
  • Hourly score update = amount calculated above and recently voted = false.

I also read here that I can execute MapReduce in a subordinate DB by running db.getMongo (). setSlaveOk () before M / R. Can I start reduction on a slave and update the main database?

Are in-place updates possible with Mongo MapReduce?

+6
source share
1 answer

Can you do this. I will solve your questions in turn:

1. You can specify a request along with the reduction of your map, which filters the set of objects that will be transferred to the map phase. In the mongo shell, it will look (provided that m and r are the names of your display and reducer functions, respectively):

 > db.coll.mapReduce(m, r, {query: {$or: [{"recently-voted": true}, {"hourly-score": {$gt: 0}}]}}) 

2. Step # 1 allows you to use your cartographer for all documents with at least one vote in the last hour (or with recently-voted set to true), but not all votes will be in the last hour. Therefore, you will need to filter the list in your cartographer and emit only those voices that you want to count:

 function m() { var hour_ago = new Date() - 3600000; this.votes.forEach(function (vote) { if (vote.ts > hour_ago) { emit(/* your key */, this.vote.a); } }); } 

And reduce:

 function r(key, values) { var sum = 0; values.forEach(function(value) { sum += value; }); return sum; } 

3. To update the hourly rating table, you can use the reduceOutput option to reduce the map, which will call your reducer with both the emitted values ​​and the previously saved value in the output collection (if any). The result of this pass will be saved to the output fee. It looks like this:

 > db.coll.mapReduce(m, r, {query: ..., out: {reduce: "output_coll"}}) 

In addition to decreasing the output again, you can use merge , which will only overwrite documents in the output collection with new ones (but leaving behind any documents with a _id other than the _id created by your mr task), replace , which is actually a drop-and operation -create and is the default or uses {inline: 1} , which returns the results directly to the shell or to your driver. Please note that when using {inline: 1} your results should match the size allowed for one document (16 MB in recent releases of MongoDB).

(4). You can run tasks to reduce the map to secondary ("slaves"), but since secondary users cannot accept records (which makes them secondary), you can only do this using the built-in output.

+10
source

Source: https://habr.com/ru/post/895103/


All Articles