Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB: Updating documents using data from the same document [duplicate]

Tags:

mongodb

I have a list of documents, each with lat and lon properties (among others).

{ 'lat': 1, 'lon': 2, someotherdata [...] }  { 'lat': 4, 'lon': 1, someotherdata [...] } [...] 

I want to modify it so that it looks like this:

{ 'coords': {'lat': 1, 'lon': 2}, someotherdata [...]}  { 'coords': {'lat': 4, 'lon': 1}, someotherdata [...]} [...] 

So far I've got this:

db.events.update({}, {$set : {'coords': {'lat': db.events.lat, 'lon': db.events.lon}}}, false, true) 

But it treats the db.events.lat and db.events.lon as strings. How can I reference the document's properties?

Cheers.

like image 708
Pawel Decowski Avatar asked Sep 24 '10 14:09

Pawel Decowski


People also ask

What is the difference between update and Upsert in MongoDB?

In MongoDB, upsert is an option that is used for update operation e.g. update(), findAndModify(), etc. Or in other words, upsert is a combination of update and insert (update + insert = upsert).

Is it possible to update MongoDB field using value of another field?

The way we do this is by $project ing our documents and using the $concat string aggregation operator to return the concatenated string. You then iterate the cursor and use the $set update operator to add the new field to your documents using bulk operations for maximum efficiency.


2 Answers

Update: If all you have to do is change the structure of a document without changing the values, see gipset's answer for a nice solution.


According to a (now unavailable) comment on the Update documentation page, you cannot reference the current document's properties from within an update().

You'll have to iterate through all the documents and update them like this:

db.events.find().snapshot().forEach(   function (e) {     // update document, using its own properties     e.coords = { lat: e.lat, lon: e.lon };      // remove old properties     delete e.lat;     delete e.lon;      // save the updated document     db.events.save(e);   } ) 

Such a function can also be used in a map-reduce job or a server-side db.eval() job, depending on your needs.

like image 93
Niels van der Rest Avatar answered Oct 03 '22 14:10

Niels van der Rest


The $rename operator (introduced a month after this question was posted) makes it really easy to do these kinds of things where you don't need to modify the values.

Insert some test documents

db.events.insert({ 'lat': 1, 'lon': 2, someotherdata: [] }) db.events.insert({ 'lat': 4, 'lon': 1, someotherdata: [] }) 

use the $rename operator

db.events.update({}, {$rename: {'lat': 'coords.lat', 'lon': 'coords.lon'}}, false, true) 

Results

db.events.find() {     "_id" : ObjectId("5113c82dd28c4e8b79971add"),     "coords" : {         "lat" : 1,         "lon" : 2     },     "someotherdata" : [ ] } {     "_id" : ObjectId("5113c82ed28c4e8b79971ade"),     "coords" : {         "lat" : 4,         "lon" : 1     },     "someotherdata" : [ ] } 
like image 35
gipset Avatar answered Oct 03 '22 14:10

gipset