Подтвердить что ты не робот

Как заменить строку во всех документах в Mongo

Мне нужно заменить строку в определенных документах. У меня есть код Google, но он, к сожалению, ничего не меняет. Я не уверен в синтаксисе строки ниже:

pulpdb = db.getSisterDB("pulp_database");
var cursor = pulpdb.repos.find();
while (cursor.hasNext()) {
  var x = cursor.next();
  x['source']['url'].replace('aaa', 'bbb'); // is this correct?
  db.foo.update({_id : x._id}, x);
}

Я хотел бы добавить некоторые отладочные отпечатки, чтобы узнать, что это за значение, но у меня нет опыта с MongoDB Shell. Мне просто нужно заменить это:

{ "source": { "url": "http://aaa/xxx/yyy" } }

с

{ "source": { "url": "http://bbb/xxx/yyy" } }
4b9b3361

Ответ 1

Это не исправляет вообще: если у вас есть строка http://aaa/xxx/aaa (yyy равна aaa), вы получите http://bbb/xxx/bbb. Но если вы справитесь с этим, код будет работать.

Чтобы добавить функцию отладки, используйте функцию print:

var cursor = db.test.find();
while (cursor.hasNext()) {
  var x = cursor.next();
  print("Before: "+x['source']['url']);
  x['source']['url'] = x['source']['url'].replace('aaa', 'bbb');
  print("After: "+x['source']['url']);
  db.test.update({_id : x._id}, x);
}

(И, кстати, если вы хотите распечатать объекты, есть также функция printjson)

Ответ 2

MongoDB может выполнять поиск и замену строки с помощью mapreduce. Да, для этого вам нужна очень специальная структура данных - вы не можете ничего иметь в верхних клавишах, но вам нужно хранить все под поддокументом value. Вот так:

{
    "_id" : ObjectId("549dafb0a0d0ca4ed723e37f"),
    "value" : {
            "title" : "Top 'access denied' errors",
            "parent" : "system.admin_reports",
            "p" : "\u0001\u001a%"
    }
}

После того, как вы настроите эту настройку, вы можете:

$map = new \MongoCode("function () {
  this.value['p'] = this.value['p'].replace('$from', '$to');
  emit(this._id, this.value);
}");
$collection = $this->mongoCollection();
// This won't be called.
$reduce = new \MongoCode("function () { }");
$collection_name = $collection->getName();
$collection->db->command([
  'mapreduce' => $collection_name,
  'map' => $map,
  'reduce' => $reduce,
  'out' => ['merge' => $collection_name],
  'query' => $query,
  'sort' => ['_id' => 1],
]);

Ответ 3

Лучший способ сделать это, если вы находитесь на MongoDB 2.6 или новее, - это цикл над объектом курсора с помощью метода .forEach и обновления каждый документ usin "bulk" для максимальной эффективности.

var bulk = db.collection.initializeOrderedBulkOp();
var count = 0;

db.collection.find().forEach(function(doc) {
    print("Before: "+doc.source.url);
    bulk.find({ '_id': doc._id }).update({
        '$set': { 'source.url': doc.source.url.replace('aaa', 'bbb') }
    })
    count++;
    if(count % 200 === 0) {
        bulk.execute();
        bulk = db.collection.initializeOrderedBulkOp();
    }

// Clean up queues
if (count > 0) 
    bulk.execute();

Из MongoDB 3.2 Массовый() API и связанные с ней методы , вам нужно будет использовать db.collection.bulkWrite().

Вам понадобится цикл над курсором, динамически создайте запрос и $push каждую операцию в массив.

var operations = [];
db.collection.find().forEach(function(doc) {
    print("Before: "+doc.source.url);
    var operation = {
        updateOne: { 
            filter: { '_id': doc._id }, 
            update: { 
                '$set': { 'source.url': doc.source.url.replace('aaa', 'bbb') }
            }
        }
    };
    operations.push(operation);
})
operations.push({ 
    ordered: true, 
    writeConcern: { w: "majority", wtimeout: 5000 } 
})

db.collection.bulkWrite(operations);