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

Как удалить дубликаты на основе ключа в Mongodb?

У меня есть коллекция в MongoDB, где есть (~ 3 миллиона записей). Моя запись будет выглядеть так:

 { "_id" = ObjectId("50731xxxxxxxxxxxxxxxxxxxx"),
   "source_references" : [
                           "_id" : ObjectId("5045xxxxxxxxxxxxxx"),
                           "name" : "xxx",
                           "key" : 123
                          ]
 }

У меня есть много дубликатов записей в коллекции, имеющих те же source_references.key. (По Duplicate я имею в виду source_references.key не _id).

Я хочу удалить повторяющиеся записи на основе source_references.key, я подумываю написать некоторый PHP-код для прохождения каждой записи и удалить запись, если она существует.

Есть ли способ удалить дубликаты в внутренней командной строке Mongo?

4b9b3361

Ответ 1

Если вы уверены, что source_references.key идентифицирует повторяющиеся записи, вы можете обеспечить уникальный индекс с помощью опции dropDups:true в MongoDB 2.6 и старше:

db.things.ensureIndex({'source_references.key' : 1}, {unique : true, dropDups : true})

Это сохранит первый уникальный документ для каждого значения source_references.key и отбросит любые последующие документы, которые в противном случае вызывают нарушение дублирующего ключа.

Важные примечания:

  • Параметр dropDups был удален в MongoDB 3.0, поэтому потребуется другой подход. Например, вы можете использовать агрегацию, как было предложено: MongoDB дублировать документы даже после добавления уникального ключа.
  • Любые документы, отсутствующие в поле source_references.key, будут считаться имеющими нулевое значение, поэтому последующие документы, пропускающие поле ключа, будут удалены. Вы можете добавить параметр sparse:true, чтобы индекс применялся только к документам с полем source_references.key.

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

Ответ 2

Это самый простой запрос, который я использовал на моем MongoDB 3.2

db.myCollection.find({}, {myCustomKey:1}).sort({_id:1}).forEach(function(doc){
    db.myCollection.remove({_id:{$gt:doc._id}, myCustomKey:doc.myCustomKey});
})

Покажите свой customKey перед запуском, чтобы увеличить скорость

Ответ 3

Удалить дубликаты структура агрегации.

а. Если вы хотите удалить за один раз.

var duplicates = [];

db.collectionName.aggregate([
  // discard selection criteria, You can remove "$match" section if you want
  { $match: { 
    source_references.key: { "$ne": '' }  
  }},
  { $group: { 
    _id: { source_references.key: "$source_references.key"}, // can be grouped on multiple properties 
    dups: { "$addToSet": "$_id" }, 
    count: { "$sum": 1 } 
  }}, 
  { $match: { 
    count: { "$gt": 1 }    // Duplicates considered as count greater than one
  }}
])               // You can display result until this and check duplicates 
.forEach(function(doc) {
    doc.dups.shift();      // First element skipped for deleting
    doc.dups.forEach( function(dupId){ 
        duplicates.push(dupId);   // Getting all duplicate ids
        }
    )    
})

// If you want to Check all "_id" which you are deleting else print statement not needed
printjson(duplicates);     

// Remove all duplicates in one go    
db.collectionName.remove({_id:{$in:duplicates}})

б. Вы можете удалять документы по одному.

db.collectionName.aggregate([
  // discard selection criteria, You can remove "$match" section if you want
  { $match: { 
    source_references.key: { "$ne": '' }  
  }},
  { $group: { 
    _id: { source_references.key: "$source_references.key"}, // can be grouped on multiple properties 
    dups: { "$addToSet": "$_id" }, 
    count: { "$sum": 1 } 
  }}, 
  { $match: { 
    count: { "$gt": 1 }    // Duplicates considered as count greater than one
  }}
])               // You can display result until this and check duplicates 
.forEach(function(doc) {
    doc.dups.shift();      // First element skipped for deleting
    db.collectionName.remove({_id : {$in: doc.dups }});  // Delete remaining duplicates
})

Ответ 4

Хотя @Stennie является действительным ответом, это не единственный способ. Infact руководство MongoDB просит вас быть очень осторожным при этом. Есть еще две опции

Ответ 5

pip install mongo_remove_duplicate_indexes

  • создать script на любом языке
  • итерация по вашей коллекции
  • создайте новую коллекцию и создайте новый индекс в этой коллекции с уникальным значением true, помните, что этот индекс должен быть таким же, как индекс u хочет удалить дубликаты из оригинальной коллекции ur с тем же именем для ex-u есть коллекция игр, и в этой коллекции у есть жанр поля, который содержит дубликаты, которые вы хотите удалить, поэтому просто создайте новую коллекцию db.createCollection( "CNAME" ) создать новый индекс db.cname.createIndex({ 'жанр': 1}, уникальный: 1) теперь, когда u будет вставлять документ с похожим жанром, только первый будет принят, другой будет отклонен с ошибкой ключа duplicae.
  • теперь просто вставляем значения формата json u, полученные в новую коллекцию и обрабатываем исключение, используя обработку исключений для ex pymongo.errors.DuplicateKeyError

проверьте исходный код пакета для mongo_remove_duplicate_indexes для лучшего понимания

Ответ 6

Если у вас достаточно памяти, вы можете в scala сделать что-то вроде этого:

cole.find().groupBy(_.customField).filter(_._2.size>1).map(_._2.tail).flatten.map(_.id)
.foreach(x=>cole.remove({id $eq x})

Ответ 7

Вот несколько более "ручной" способ сделать это:

По сути, сначала получите список всех уникальных ключей, которые вам интересны.

Затем выполните поиск с использованием каждого из этих ключей и удалите, если этот поиск вернется больше одного.

    db.collection.distinct("key").forEach((num)=>{
      var i = 0;
      db.collection.find({key: num}).forEach((doc)=>{
        if (i)   db.collection.remove({key: num}, { justOne: true })
        i++
      })
    });