0

i have a sample mongodb like this:

{
        "_id" : ObjectId("559e448dfb9fc95e5d00008c"),
        "title" : "Maps ",
        "link" : "https://www.youtube.com/embed/NmugSMBh_iI",
        "img" : "https://i.ytimg.com/vi/NmugSMBh_iI/default.jpg",
        "time" : "3:28",
        "des" : "Maroon 5 - Maps (Explicit)\r\n",
        "cat" : [
                "maroon5"
        ],
        "id" : 179,
        "date" : "2015-07-08T16:49:11+07:00"
}
{
        "_id" : ObjectId("559e451afb9fc95e5d00008d"),
        "title" : "Animals",
        "link" : "https://www.youtube.com/embed/qpgTC9MDx1o",
        "img" : "https://i.ytimg.com/vi/qpgTC9MDx1o/default.jpg",
        "time" : "4:40",
        "des" : "Maroon 5 - Animals\r\n",
        "cat" : [
                "maroon5"
        ],
        "id" : 180,
        "date" : "2015-07-08T16:49:11+07:00"
}

Now i want to replace this string "embed/" to "watch?v=" in each "link" field, like this:

"link" : "https://www.youtube.com/watch?v=/NmugSMBh_iI"

How can i do it ?

Blakes Seven
  • 49,422
  • 14
  • 129
  • 135
Thanhtu150
  • 91
  • 2
  • 16
  • Not without looping. MongoDB updates cannot examine the existing value of a field atmoically. You need to read each document to get the value, alter it and `$set` the property to the altered value. – Blakes Seven Jul 10 '15 at 04:09

2 Answers2

2

You're going to have to loop through it and change them one by one. You can use the following code to make the changes in your database but alternatively, you can use supporting library for MongoDB for any language you want to achieve the same result.

var cursor = db.videos.find();
while ( cursor.hasNext() ) {
   var current = cursor.next();
   db.videos.update({_id: current._id}, {$set: {link: current.link.replace('embed/','watch?v=')}})
}
Peyman
  • 3,059
  • 1
  • 33
  • 68
1

As stated, you need to loop the collection results in order to be able to read the values you want to modify. MongoDB update operators do not support doing this "in place" and there is nothing such as a "regexReplce" operator presently supported. Though it would be nice.

Your most efficient way of doing this is with the "Bulk" operations API, and a little query filtering via $regex to make sure you are only updating those items that need updating:

var bulk = db.tube.initializeUnorderedBulkOp(),
    count = 0;

db.tube.find({ 
   "link": /(youtube\.com)(\/embed)/ 
}).forEach(function(doc) {
    doc.link = doc.link.replace( 
        new RegExp("(youtube\.com)(\/embed\/)"), 
        new RegExp("$1/watch\?v=") );

    bulk.find({ "_id": doc._id }).updateOne({ "$set": { "link": doc.link } });
    count++;

    // Only send operations to server once in 1000 ops. And re-init.
    if ( count % 1000 == 0 ) {
        bulk.execute();
        bulk = db.tube.initializeUnorderedBulkOp();
    }
});

// Drain any queued operations
if ( count % 1000 != 0 )
    bulk.execute();

It's your fastest way of updating since the requests are processed in "batches" and that means less traffic both to and from the server. Ergo, more speed.

Blakes Seven
  • 49,422
  • 14
  • 129
  • 135