Sameer Shaikh
Sameer Shaikh

Reputation: 265

Replace a word from a string

I have mongodb documents with a field like this:

Image : http://static14.com/p/Inc.5-Black-Sandals-5131-2713231-7-zoom.jpg

How can I replace the zoom part in the string value with some other text in order to get:

Image : http://static14.com/p/Inc.5-Black-Sandals-5131-2713231-7-product2.jpg

Upvotes: 6

Views: 10852

Answers (3)

Xavier Guihot
Xavier Guihot

Reputation: 61774

Nowadays,

  • starting Mongo 4.2, db.collection.updateMany (alias of db.collection.update) can accept an aggregation pipeline, finally allowing the update of a field based on its own value.
  • starting Mongo 4.4, the new aggregation operator $replaceOne makes it very easy to replace part of a string.
// { "Image" : "http://static14.com/p/Inc.5-Black-Sandals-5131-2713231-7-zoom.jpg" }
// { "Image" : "http://static14.com/p/Inc.5-Black-Sandals-5131-2713231-7-boom.jpg" }
db.collection.updateMany(
  { "Image": { $regex: /zoom/ } },
  [{
    $set: { "Image": {
      $replaceOne: { input: "$Image", find: "zoom", replacement: "product2" }
    }}
  }]
)
// { "Image" : "http://static14.com/p/Inc.5-Black-Sandals-5131-2713231-7-product2.jpg" }
// { "Image" : "http://static14.com/p/Inc.5-Black-Sandals-5131-2713231-7-boom.jpg" }
  • The first part ({ "Image": { $regex: /zoom/ } }) is just there to make the query faster by filtering which documents to update (the ones containing "zoom")
  • The second part ($set: { "Image": {...) is the update aggregation pipeline (note the squared brackets signifying the use of an aggregation pipeline):
    • $set is a new aggregation operator (Mongo 4.2) which in this case replaces the value of a field.
    • The new value is computed with the new $replaceOne operator. Note how Image is modified directly based on the its own value ($Image).

Upvotes: 0

chridam
chridam

Reputation: 103475

You could use mongo's forEach() cursor method to do an atomic update with the $set operator :

db.collection.find({}).snapshot().forEach(function(doc) {
    var updated_url = doc.Image.replace('zoom', 'product2');
    db.collection.update(
        {"_id": doc._id}, 
        { "$set": { "Image": updated_url } }
    );
});

Given a very large collection to update, you could speed up things a little bit with bulkWrite and restructure your update operations to be sent in bulk as:

var ops = [];
db.collection.find({}).snapshot().forEach(function(doc) {
    ops.push({
        "updateOne": {
            "filter": { "_id": doc._id },
            "update": { "$set": { "Image": doc.Image.replace('zoom', 'product2') } }
        }
    });

    if ( ops.length === 500 ) {
        db.collection.bulkWrite(ops);
        ops = [];
    }
})

if ( ops.length > 0 )  
    db.collection.bulkWrite(ops);

Upvotes: 8

Abby
Abby

Reputation: 3209

db.myCollection.update({image: 'http://static14.com/p/Inc.5-Black-Sandals-5131-2713231-7-zoom.jpg'}, {$set: {image : 'http://static14.com/p/Inc.5-Black-Sandals-5131-2713231-7-product2.jpg'}})

If you need to do this multiple times to multiple documents, you need to iterate them with a function. See here: MongoDB: Updating documents using data from the same document

Upvotes: 0

Related Questions