使用表达式而不是值更新

时间:2012-04-16 19:52:08

标签: mongodb

我对MongoDB完全不熟悉......我错过了一个“新手”标签,所以专家们不必看到这个问题。

我正在尝试使用表达式更新集合中的所有文档。我期望解决的问题是:

db.QUESTIONS.update({}, { $set: { i_pp : i_up * 100 - i_down * 20 } }, false, true);

然而,这会导致以下错误消息:

  

ReferenceError:未定义i_up(shell):1

与此同时,数据库吃这个没有任何问题:

db.QUESTIONS.update({}, { $set: { i_pp : 0 } }, false, true);

我是否必须同时执行此一个文档?这似乎过于复杂。

更新 谢谢Sergio Tulentsev告诉我它不起作用。现在,我真的在努力解决这个问题。我向有用的灵魂提供500 Profit Points,他可以用MongoDB理解的方式写这个。如果您在our forum注册,我可以将利润点添加到您的帐户。

5 个答案:

答案 0 :(得分:5)

您无法在更新中使用表达式。或者,您不能使用依赖于文档字段的表达式。简单的自包含数学表达式很好(例如2 * 2)。

如果要为所有与其他字段相关的文档设置新字段,则必须循环它们并手动更新。多重更新在这里无济于事。

答案 1 :(得分:4)

我在搜索MongoDB等效的SQL时遇到了这个:

update t
set c1 = c2
where ...

Sergio是正确的,您无法在直接更新中将其他属性作为值引用。但是,db.c.find(...)会返回cursor and that cursor has a forEach method

  

对MongoDB的查询返回一个游标,可以迭代该游标进行检索   结果。查询的确切方式因语言驱动程序而异。   下面的细节集中在来自MongoDB shell的查询(即   mongo过程)。

     

shell find()方法返回一个游标对象,然后我们可以迭代它以从结果中检索特定文档。我们用   用于此目的的hasNext()next()方法。

for( var c = db.parts.find(); c.hasNext(); ) {
   print( c.next());
}
     

此外,在shell中,forEach()可以与游标一起使用:

db.users.find().forEach( function(u) { print("user: " + u.name); } );

所以你可以这样说:

db.QUESTIONS.find({}, {_id: true, i_up: true, i_down: true}).forEach(function(q) {
    db.QUESTIONS.update(
        { _id: q._id },
        { $set: { i_pp: q.i_up * 100 - q.i_down * 20 } }
    );
});

在不离开MongoDB的情况下一次更新一个。

如果你使用驱动程序连接到MongoDB,那么应该有一些方法可以将一串JavaScript发送到MongoDB;例如,使用Ruby驱动程序,您可以使用eval

connection.eval(%q{
    db.QUESTIONS.find({}, {_id: true, i_up: true, i_down: true}).forEach(function(q) {
        db.QUESTIONS.update(
            { _id: q._id },
            { $set: { i_pp: q.i_up * 100 - q.i_down * 20 } }
        );
    });
})

其他语言应该类似。

答案 2 :(得分:1)

Rha7提出了一个好主意,但如果没有定义临时变量,上面的代码就无法工作。

此示例代码基于生日'生成近似的年龄计算(场景背后的闰年)。字段并将值插入到不包含此类的所有文档的适当字段中:

db.employers.find({age: {$exists: false}}).forEach(function(doc){
    var new_age = parseInt((ISODate() - doc.birthday)/(3600*1000*24*365));
    db.employers.update({_id: doc._id}, {$set: {age: new_age}});
});

答案 3 :(得分:0)

从来电者ID开头删除“00”的示例:

db.call_detail_records_201312.find(
    { destination: /^001/ }, 
    { "destination": true }
).forEach(function(row){
    db.call_detail_records_201312.update(
        { _id: row["_id"] },
        { $set: {
                destination: row["destination"].replace(/^001/, '1')
            }
        }
    )
});

答案 4 :(得分:0)

//the only differnce is to make it look like and aggregation pipeline
db.table.updateMany({}, [{
      $set: {
        col3:{"$sum":["$col1","$col2"]}
      },
    }]
 )