Как заменить строку во всех документах в 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" } }
Ответы
Ответ 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);