Reputation: 113
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
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
Reputation: 3655
[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