2012-11-20 82 views
2

我有一个MongoDB的集合,如下所示:更新MongoDB记录会重写整个记录还是仅更新字段?

comment_id (number) 
comment_title (text) 
score (number) 
time_score (number) 
final_score (number) 
created_time (timestamp) 

分数是和整数,这通常用$ INC 1或更新每当有人或票上下该记录-1。 但time_score更新使用函数相对于时间戳和当前时间和其他因素,如多少(整天通过)和多少(整个星期过去).....等

所以我做$ inc和$直接对数据库进行分析,但对于time_score,我从db中获取数据,计算新分数并将其写回。我担心的是,如果许多用户在计算time_score期间递增“score”字段,那么当我将time_score写入db时,它将破坏最后一个score值。

要更清楚地更新Mongo记录中的特定字段是否会重写整个记录或仅更新字段? (假设所有这些字段都被索引)。

回答

2

默认情况下,整个文档被重写。要指定更改的字段而不修改其他内容,请使用$set运算符。

编辑:该答案的评论是正确的 - 任何update modifiers将导致只有相关领域被重写,而不是整个文件。通过“默认”,我的意思是没有使用特殊修饰符的情况(提供了一个vanilla文档)。

+1

这是不准确的 - 当您使用各种运算符(如$ inc)时,只会更改指定的字段。只有当您传递完整文档以进行更新而没有任何更新操作员时,整个文档才会被重写。 –

+0

实际上,每一个更新操作符都只会修改它应用的字段。覆盖整个文档是例外而不是规则,因为很少有人想要在现实世界中覆盖整个文档。 –

+0

你们中的任何人都可以发布一个链接给我,以验证这是如何完成更新! – Shashank

0

您所描述的算法绝对不是线程安全的。

当您阅读整个文档时,更改一个字段,然后回写整个文档,您正在创建竞争条件 - 文档中的任何字段在读取之后修改,但写入之前将被您的更新覆盖。

这是使用$ set或$ inc操作符自动设置单个字段而不是根据可能过时的值更新整个文档的众多原因之一。

另一个原因是设置/更新单个字段“in-place”比写入整个文档更有效率。另外,当传递较小的更新文档({$ set:{field:value}},而不是文档的整个新版本)时,您的网络负载较低。

+0

不,你错了,你没有得到我的问题我不是说我会写整个文件我说我不想这样做,上面的答案是正确的。 – Shehabix

+1

您所描述的算法对于任何不执行原子更新的操作都不是线程安全的。 $ inc是安全的,但是基于可能过时的值的$ set是不安全的。 –

+0

如果价值是一个不是特定数字的计算,我该怎么办?我可以在mongo中做这样的事情: $ set:{field:equation * field - another_field}? – Shehabix