Update using an expression instead of a value

I am completely unfamiliar with MongoDB ... I miss the "newbie" tag, so experts would not need to see this question.

I am trying to update all documents in a collection using an expression. The query I was expecting to resolve was as follows:

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

This, however, leads to the following error message:

ReferenceError: i_up not defined (shell): 1

At the same time, there were no food problems in the database:

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

Should I do this document at a time or something else? It just seems overly complicated.

Update Thanks to Sergio Tulentsev for telling me that this will not work. Now I am really struggling with how to do this. I offer a 500 "Profit" to a helpful soul who can write it the way MongoDB understands it. If you register on our forum , I can add profit points to your account.

+2
source share
4 answers

You cannot use expressions in updates. Or rather, you cannot use expressions that depend on document fields. Simple self-consistent math expressions are exact (e.g. 2 * 2 ).

If you want to set a new field for all documents that are functions of other fields, you need to sort them out and update them manually. Multi-update will not help here.

+3
source

I just came across this looking for the equivalent of MongoDB SQL code as follows:

 update t set c1 = c2 where ... 

Sergio is correct that you cannot refer to another property as a value in a direct update. However, db.c.find(...) returns a cursor, and this cursor has a forEach method :

Queries on MongoDB return a cursor that can be repeated to retrieve the results. The exact request method depends on the language driver. The details below focus on MongoDB shell requests (i.e. mongo ).

The find() shell method returns a cursor object, which you can then iterate over to extract specific documents from the result. We use hasNext() and next() for this purpose.

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

In addition, in the forEach() shell it can be used with a cursor:

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

So you can say the following:

 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 } } ); }); 

to update them one at a time without leaving MongoDB.

If you are using a driver to connect to MongoDB, then there must be some way to send a JavaScript string to MongoDB; for example with a Ruby driver that you would use 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 } } ); }); }) 

Other languages ​​should be similar.

+4
source

Example of removing “00” from the beginning of the caller ID:

 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') } } ) }); 
0
source

Rha7 gave a good idea, but the code above does not work without defining a temporary variable.

This code example gives an approximate calculation of the age (leap years behind the scene) based on the "birthday" field and inserts the value into the appropriate field for all documents that do not contain such:

 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}}); }); 
0
source

Source: https://habr.com/ru/post/1393081/


All Articles