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

У меня есть много документов mongodb в коллекции вида:

{
....
"URL":"www.abc.com/helloWorldt/..."
.....
}

Я хочу заменить helloWorldt на helloWorld чтобы получить:

{
....
"URL":"www.abc.com/helloWorld/..."
.....
}

Как я могу добиться этого для всех документов в моей коллекции?

Ответ 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);
});

Ответ 2

В настоящее время вы не можете использовать значение поля для его обновления. Таким образом, вам придется перебирать документы и обновлять каждый документ с помощью функции. Вот пример того, как вы можете это сделать здесь: MongoDB: Обновление документов с использованием данных из того же документа

Ответ 3

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});
  });
});

Ответ 4

Чтобы заменить ВСЕ вхождения подстроки в вашем документе, используйте:

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);
});

Ответ 5

Форматирование моего комментария к выбранному ответу (ответ @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));
})

Ответ 6

Теперь вы можете это сделать!

Мы можем использовать 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);

  }
}

Надеюсь это поможет!

Ответ 7

Использование mongodump, bsondump и mongoimport.

Иногда коллекции 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/

Ответ 8

На всякий случай, если вы используете примеры из ответов здесь и получаете "Обновлено 0 существующих записей" при запуске скрипта замены, проверьте, подключен ли ваш клиент к основному узлу MongoDB, который позволяет хранить/записывать изменения.

Ответ 9

Вы можете попробовать ниже конвейер агрегации в версии 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(); 
 }

Ответ 10

Начиная с 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 }, иначе будет обновлен только первый соответствующий документ.