我有一个MongoDB集合,如下所示:
comment_id (number)
comment_title (text)
score (number)
time_score (number)
final_score (number)
created_time (timestamp)
分数是和整数,通常使用$ inc 1或-1更新,只要有人为该记录投票或者投票。 但是time_score是使用相对于时间戳和当前时间的函数以及其他因素来更新的,例如有多少(整天过去了)和多少(整整一周过去了)......等等
所以我直接对db执行$ inc和$ dec但是对于time_score,我从db检索数据计算新分数并将其写回。我担心的是,如果许多用户在计算time_score期间增加了“得分”字段,那么当我将time_score写入db时,它将破坏得分的最后一个值。
更清楚的是,更新Mongo中记录中的特定字段会重写整个记录还是仅更新更新的字段? (假设所有这些字段都已编入索引)。
答案 0 :(得分:2)
默认情况下,会重写整个文档。要指定更改的字段而不修改任何其他内容,请使用$set运算符。
编辑:对此答案的评论是正确的 - 任何update modifiers都只会导致重写相关字段而不是整个文档。通过"默认",我的意思是没有使用特殊修饰符的情况(提供了一个香草文档)。
答案 1 :(得分:0)
您描述的算法绝对不是线程安全的。
当您阅读整个文档时,更改一个字段然后回写整个文档,您将创建一个竞争条件 - 文档中的任何字段在您的读取之后但在您的写入被更新覆盖之前被修改。
这是使用$ set或$ inc运算符以原子方式设置单个字段而不是根据其中可能过时的值更新整个文档的众多原因之一。
另一个原因是“就地”设置/更新单个字段比编写整个文档更有效。此外,当您传递较小的更新文档({$ set:{field:value}}而不是整个新版本的文档时),网络上的负载会减少。