fertapric
fertapric

Reputation: 113

self referencing update using MongoDB

I wonder if there is a way to make a self referencing update in MongoDB, so you can use object's params on a $set query. Here is an example:

> db.labels.save({"name":"label1", "test":"hello"})
> db.labels.save({"name":"label2", "test":"hello"})
> db.labels.save({"name":"label3", "test":"hello"})
> db.labels.find()
{ "_id" : ObjectId("4f1200e2f8509434f1d28496"), "name" : "label1", "test" : "hello" }
{ "_id" : ObjectId("4f1200e6f8509434f1d28497"), "name" : "label2", "test" : "hello" }
{ "_id" : ObjectId("4f1200eaf8509434f1d28498"), "name" : "label3", "test" : "hello" }

I saw that you can use this syntax on $where queries: http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-JavascriptExpressionsand%7B%7B%24where%7D%7D

> db.myCollection.find( { a : { $gt: 3 } } ); 
> db.myCollection.find( { $where: "this.a > 3" } );
> db.myCollection.find("this.a > 3");
> f = function() { return this.a > 3; } db.myCollection.find(f);

So, I tried with:

db.labels.update({"test":"hola"}, {$set : {"test": this.name})

but it didn't work.

The expected result is:

{ "_id" : ObjectId("4f1200e2f8509434f1d28496"), "name" : "label1", "test" : "label1" }
{ "_id" : ObjectId("4f1200e6f8509434f1d28497"), "name" : "label2", "test" : "label2" }
{ "_id" : ObjectId("4f1200eaf8509434f1d28498"), "name" : "label3", "test" : "label3" }

Any thoughts? Thanks in advance

Upvotes: 10

Views: 8496

Answers (2)

RameshVel
RameshVel

Reputation: 65877

Update:

It can be done by now using

db.labels.updateMany(
   {"test":"hola"},
   [{ $set: { test: "$name" }}],
)

Old Answer

At present there is no straight way to do that. But you can workaround this by

    db.labels.find({"test":"hola"}).forEach(function (doc) {
           doc.test = doc.name;
           db.labels.save(doc); 
    })

Upvotes: 22

user3616725
user3616725

Reputation: 3655

new in MongoDB 4.2

[FYI] Below approach avoids row-by-row operations (which can cause performance issues), and shifts the processing load onto the DB itself.

"Starting in MongoDB 4.2, the db.collection.update() method can accept an aggregation pipeline that specifies the modifications to perform." docs

The pipeline has access to each documents' fields, thus allowing self-referencial updates.
Please see the documentation on this, which includes an example of this sort of update.

Following the example from the OP's question the update would be:

db.labels.update(
   {"test":"hello"},
   [{ $set: { test: "$name" }}],
   { multi: true }
);

Please note that the $set used in the pipeline refers to the aggregation stage $set, and not the update operator $set.

For those familiar with the aggregate pipeline in earlier MongoDB versions: the $set stage is an alias for $addFields.

Upvotes: 4

Related Questions