mongodb: глобально заменить все ссылки на один ObjectID другим?

Итак, у меня есть база данных MongoDB с миллионами записей в нескольких коллекциях. Вот (значительно упрощенный) пример некоторых записей...

Документы коллекции А выглядят так:

{ 
  _id: ObjectID(....)
  name: "Hubert Humphrey"
}

Документы коллекции B выглядят так:

{
  _id: ObjectID(....)
  ReferenceSummary: [
    { 
      person: ObjectID(<some-ID-from-Collection-A>)
      count: 312
    },
    { 
      person: ObjectID(<some-other-ID-from-Collection-A>)
      count: 42
    },
    ...
  ], 
  TopPeople: [ ObjectID(<another-ID-from-Collection-A>), ObjectID(<yet-another-ID-from-Collection-A>), ...]
}

Теперь вот проблема. Мы поняли, что у нас есть несколько дубликатов (всего 3 или 4) в Коллекции А. И на каждую из них сотни тысяч раз ссылаются в Коллекции Б.

Однако не бывает случаев, когда данный документ Коллекции Б ссылается на два разных документа Коллекции А, которые дублируют друг друга.

Итак, что мне нужно сделать, чтобы исправить это: для каждой пары дубликатов в коллекции A с _id ObjectId(X) и ObjectId(Y) заменить все вхождения ObjectId(Y) на ObjectId(X) для всех документов в коллекции B.

Если бы я имел дело с необработанными файлами JSON, я бы просто сделал замену строки и покончил с этим.

Есть ли простой способ сделать это в оболочке mongo, просто используя одну команду для каждого из дубликатов коллекции A?


person DanM    schedule 13.06.2016    source источник
comment
Я предполагаю, что этот человек является дубликатом - у вас есть способ выбрать дубликаты (это по полю идентификатора или другим метаданным?)   -  person profesor79    schedule 14.06.2016
comment
Это всего лишь несколько конкретных дубликатов, вызванных ошибками ручного ввода. Простой способ заменить все ссылки на одну из них за раз поможет.   -  person DanM    schedule 14.06.2016


Ответы (1)


Самый простой способ выполнить эту работу — использовать цикл forEach.

var ids = [id1, id2, ...., idN];
var idsToReplace = [id1TR, id2TR, ...., IdNTR];
var aLenght = ids.lenght;

for (var i = o; i < aLenght; i++) {
    db.collectionA.find({
        _id : ids[i]
    }).forEach(function (doc) {
        doc.fieldA = idsToReplace[i];
        // if we habve an array entry we need to iterate thru it
        var arrayXLenght = doc.arrayX.lenght;
        for (var j = 0; j < arrayXLenght; j++) {
            if (doc.arrayX[j].field === ids[i]) {
                doc.arrayX[j].field = idsToReplace[i];
            }
        }

        prinjson(doc); //verify changes
        //doc.save() //uncoment when you wil be assured that changes are ok
    })

    // same thing with other collection
}
person profesor79    schedule 14.06.2016
comment
ХОРОШО; надеялся, что есть простая команда, которая просто заменит каждый отдельный экземпляр, но похоже, что мне нужно выполнить цикл вручную. - person DanM; 16.06.2016