Ответ 1
db.media.find({mediaContainer:"ContainerS3"}).forEach(function(e,i) {
e.url=e.url.replace("//a.n.com","//b.n.com");
db.media.save(e);
});
У меня есть много документов mongodb в коллекции вида:
{
....
"URL":"www.abc.com/helloWorldt/..."
.....
}
Я хочу заменить helloWorldt
на helloWorld
чтобы получить:
{
....
"URL":"www.abc.com/helloWorld/..."
.....
}
Как я могу добиться этого для всех документов в моей коллекции?
db.media.find({mediaContainer:"ContainerS3"}).forEach(function(e,i) {
e.url=e.url.replace("//a.n.com","//b.n.com");
db.media.save(e);
});
В настоящее время вы не можете использовать значение поля для его обновления. Таким образом, вам придется перебирать документы и обновлять каждый документ с помощью функции. Вот пример того, как вы можете это сделать здесь: MongoDB: Обновление документов с использованием данных из того же документа
nodejs. Использование пакета mongodb из npm
db.collection('ABC').find({url: /helloWorldt/}).toArray((err, docs) => {
docs.forEach(doc => {
let URL = doc.URL.replace('helloWorldt', 'helloWorld');
db.collection('ABC').updateOne({_id: doc._id}, {URL});
});
});
Чтобы заменить ВСЕ вхождения подстроки в вашем документе, используйте:
db.media.find({mediaContainer:"ContainerS3"}).forEach(function(e,i) {
var find = "//a.n.com";
var re = new RegExp(find, 'g');
e.url=e.url.replace(re,"//b.n.com");
db.media.save(e);
});
Форматирование моего комментария к выбранному ответу (ответ @Naveed) получил скремблирование - поэтому добавление этого ответа. Весь кредит идет к Наведу.
Просто восхитительно. Мое дело было - у меня есть поле, которое представляет собой массив, поэтому мне пришлось добавить дополнительный цикл.
Мой запрос:
db.getCollection("profile").find({"photos": {$ne: "" }}).forEach(function(e,i) {
e.photos.forEach(function(url, j) {
url = url.replace("http://a.com", "https://dev.a.com");
e.photos[j] = url;
});
db.getCollection("profile").save(e);
eval(printjson(e));
})
Теперь вы можете это сделать!
Мы можем использовать Mongo-скрипт для манипулирования данными "на лету". Меня устраивает!
Я использую этот скрипт для исправления моих адресных данных.
Пример текущего адреса: "№ 12, ПЯТЫЙ ПРОСВЕТ".
Я хочу удалить последнюю резервную запятую, ожидаемый новый адрес "" № 12, ПЯТЫЙ ПРОСВЕТ ".
var cursor = db.myCollection.find().limit(100);
while (cursor.hasNext()) {
var currentDocument = cursor.next();
var address = currentDocument['address'];
var lastPosition = address.length - 1;
var lastChar = address.charAt(lastPosition);
if (lastChar == ",") {
var newAddress = address.slice(0, lastPosition);
currentDocument['address'] = newAddress;
db.localbizs.update({_id: currentDocument._id}, currentDocument);
}
}
Надеюсь это поможет!
Иногда коллекции mongodb могут быть немного сложными с вложенными массивами/объектами и т.д., Где было бы относительно сложно построить циклы вокруг них. Мой обходной путь довольно сырой, но работает в большинстве сценариев, независимо от сложности коллекции.
1. Экспортируйте коллекцию с помощью mongodump в .bson
mongodump --db=<db_name> --collection=<products> --out=data/
2. Конвертировать .bson в формат .json, используя bsondump
bsondump --outFile products.json data/<db_name>/products.bson
3. Замените строки в файле .json на sed (для терминала linux) или любыми другими инструментами.
sed -i 's/oldstring/newstring/g' products.json
4. Импортируйте коллекцию .json с помощью mongoimport с тегом --drop, где он будет удалять коллекцию перед импортом.
mongoimport --db=<db_name> --drop --collection products <products.json
В качестве альтернативы вы можете использовать --uri для соединений в mongoimport и mongodump
пример
mongodump --uri "mongodb://mongoadmin:[email protected]:27017,10.148.0.8:27017,10.148.0.9:27017/my-dbs?replicaSet=rs0&authSource=admin" --collection=products --out=data/
На всякий случай, если вы используете примеры из ответов здесь и получаете "Обновлено 0 существующих записей" при запуске скрипта замены, проверьте, подключен ли ваш клиент к основному узлу MongoDB, который позволяет хранить/записывать изменения.
Вы можете попробовать ниже конвейер агрегации в версии 3.4
.
Запрос агрегирования, чтобы заменить строку поиска на заменяющую строку.
Логика состоит в том, чтобы найти строку поиска ($indexOfCP
), за которой следует $concat
чтобы соединить все части ($substrCP
), часть перед совпадающей строкой поиска, заменяющую строку и остальную исходную строку.
Массовое обновление, чтобы написать новую структуру URL.
var bulk = db.getCollection(col).initializeUnorderedBulkOp();
var count = 0;
var batch = 1;
db.getCollection(col).aggregate([
{"$project":{
"URL":{
"$let":{
"vars":{
"len":{
"$strLenCP":"helloWorldt"},"start":{"$indexOfCP":["$URL","helloWorldt"]}
},
"in":{
"$concat":[
{"$substrCP":["$URL",0,"$$start"]},
"helloWorld",
{"$substrCP":[
"$URL",
{"$add":["$$start","$$len"]},
{"$subtract":[{"$strLenCP":"$URL"},{"$add":["$$start","$$len"]}]}
]}
]
}
}
}
}}
]).forEach(function(doc){
var _id = doc._id;
var url = doc.URL;
bulk.find({ "_id" : _id }).updateOne(
{ $set: {"URL" : url } }
);
count++;
if (count == batch) {
bulk.execute();
bulk = db.getCollection(col).initializeUnorderedBulkOp();
count = 0;
}
});
if (count > 0) {
bulk.execute();
}
Начиная с Mongo 4.2
, db.collection.update()
может принять конвейер агрегации, что в конечном итоге позволяет обновить поле на основе другого поля:
// { URL: "www.abc.com/helloWorldt/..." }
// { URL: "www.abc.com/HelloWo/..." }
db.collection.update(
{ URL: { $regex: "/helloWorldt/" } },
[{
$set: { URL: {
$concat: [
{ $arrayElemAt: [ { $split: [ "$URL", "/helloWorldt/" ] }, 0 ] },
"/helloWorld/",
{ $arrayElemAt: [ { $split: [ "$URL", "/helloWorldt/" ] }, 1 ] }
]
}}
}],
{ multi: true }
)
// { URL: "www.abc.com/helloWorld/..." }
// { URL: "www.abc.com/HelloWo/..." }
Это немного многословно, так как пока нет подходящего оператора $replace
.
Первая часть { URL: { $regex: "/helloWorldt/" } }
является запросом на совпадение, фильтрующим, какие документы нужно обновить (те, с которыми неправильно написан hello world).
Вторая часть [{ $set: { URL:... } }]
- это конвейер агрегации обновлений (обратите внимание на квадратные скобки, обозначающие использование конвейера агрегации). $set
- новый оператор агрегирования, который в этом случае создает/заменяет поле. Новое значение странным образом вычисляется с использованием сочетания $concat
и $split
за отсутствия правильного строкового оператора $replace
. Обратите внимание, как URL
изменяется напрямую на основе его собственного значения ($URL
).
Не забудьте { multi: true }
, иначе будет обновлен только первый соответствующий документ.