我想定期(每隔5分钟左右)处理/更新Mongodb集合中的每个文档,并将结果保存回数据库。更新函数需要在每个文档上执行实际代码(据我所知),因为它需要执行计算,例如获取时间戳的差异并使用Math.pow
的指数,standard MongoDB update operators不盖
在NodeJS中执行此操作的最佳方法是什么?
完整背景:我正在尝试实施Hacker News ranking algorithm,这与时间有关。 discussion I've seen around this涉及使用单独的线程/进程来定期更新文档的分数。
答案 0 :(得分:2)
没有浪费来回调查,似乎你有字段我将调用points
,初始创建时间created_date
,然后是result
的ycombinator (p - 1) / (t + 2)^1.5
< / p>
最简单的是写一个非常简单的3班次mongo shell script。
db.ycombinator.find().forEach(function(doc) {
var diff = ISODate() - doc.created_date; // subtract date using some form of date ISODate is available in mongo shell
var hours = diff.tomagicalhours(); // some regulr javascript
var result = (doc.points - 1) / Math.pow((hours + 2), 1.5); // perform yc algo
db.ycombinator.update({"_id":doc._id}, {$set:{"result": result} }); // write back into same collection and field, result
})
进入文件ycombinator_update.js
,然后执行5分钟的crontab。
*/5 * * * * mongo ycombinator_update.js
在写操作期间,读取的性能会明显变慢,这取决于该集合中的记录数。
答案 1 :(得分:1)
您可以在查找时根据文档时间戳分配分数,并仅将原始时间戳保留在数据库中。由于得分无论如何都是时间戳的函数,因此评分算法可以在未修改的数据上包含指数衰减逻辑。如果要按分数搜索,则可以将分数转换为时间戳。
答案 2 :(得分:0)
此处未显示的另一个选项是 MongoDB MapReduce或Aggregation frameworks 。
这两个框架都提供了一种迭代集合中所有元素并将一些结果输出到不同集合的方法。聚合API不直接包含我们在HN算法中计算1.5指数所需的基元(无$sqrt
或$pow
),而是there is a workaround。
我不确定哪个方法对于这个用例是最有效的(以及它与MongoDB shell脚本suggested by Gabe Rainbow的比较)。
我相信下一步是在一个单独的进程中运行更新操作,该进程可以使用类似cron
的方式进行调度,也可以使用fork
通过节点应用程序本身启动更新操作以下逻辑:
On request for front page:
# when did we last update the scores for the front page?
if last_update was within last X minutes:
return list sorted by score right away
else
fork a process to sort the front page
last_update := Date.Now
return list sorted by score (either right away [stale], or after the update completes [takes a while])