Suppose I want to calculate the "popularity" field for all objects in my collection. It depends on the difference from the current time to the field "submitTime" and the numbers in the field "votes". This operation will run every hour. What's the most efficient way to run a function on all objects? Just an example, it could be any function:
function(){
this.popularity = this.votes / (Date.now() - this.submitTime);
}
If you want to run a function on all objects and save a popularity score in the original collection, your best approach is going to be iterating all the documents to calculate and save the new score. If you wanted to save to a different collection you could use a MapReduce instead.
If you are open to other ideas on how to calculate popularity, there are more options :).
To improve efficiency for your current approach you could:
$set rather than re-saving the full document.Use a popularity metric that can be determined by sorting rather than a calculation. For example: { votes: -1, lastVotedTime: -1, submitTime: -1 }. This may not meet your requirements for ageing out the popularity for old documents, though.
Use a numeric popularity metric where events and user actions (eg. article published, user views/votes/, .. ) will add different values of popularity. Over time the popularity decays. The Radioactivity module for Drupal implements this with a rules-based approach.
To implement the latter approach in MongoDB, you could:
popularity field, where new objects start at a certain value (eg 1000)$inc by appropriate amounts (for example 50 for a new vote)There are more nuances to "what is a good popularity metric", and plenty of previous questions on StackOverflow (eg: What formula should be used to determine “hot” questions?).