Jak usunąć duplikaty na podstawie klucza w Mongodb?

Mam kolekcję w MongoDB, gdzie jest około (~3 miliony płyt). Mój przykładowy zapis wyglądałby tak:

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

Mam wiele zduplikowanych rekordów w kolekcji o tym samym source_references.key. (Przez duplikat mam na myśli source_references.key nie _id).

Chcę usunąć zduplikowane rekordy na podstawie source_references.key, myślę o napisaniu kodu PHP, aby przejść każdy rekord i usunąć rekord, jeśli istnieje.

Czy istnieje sposób na usunięcie duplikatów w wewnętrznej komendzie Mongo linia?

Author: Somnath Muluk, 2012-11-02

7 answers

Jeśli jesteś pewien, że source_references.key identyfikuje zduplikowane rekordy, możesz zapewnić unikalny Indeks z dropDups:true opcja tworzenia indeksu w MongoDB 2.6 lub starszym:

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

Spowoduje to zachowanie pierwszego unikalnego dokumentu dla każdej wartości source_references.key i usunięcie kolejnych dokumentów, które w przeciwnym razie spowodowałyby złamanie duplikatu klucza.

Ważne Uwagi :

  • opcja dropDups została usunięta W MongoDB 3.0 , więc inne podejście będzie wymagane. Na przykład, możesz użyć agregacji zgodnie z sugestią na: MongoDB duplicate documents nawet po dodaniu unikalnego klucza .
  • wszelkie dokumenty, w których brakuje pola source_references.key, będą traktowane jako posiadające wartość null , więc kolejne dokumenty, w których brakuje pola klucza, zostaną usunięte. Możesz dodać sparse:true opcja tworzenia indeksu, więc indeks ma zastosowanie tylko do dokumentów z polem source_references.key.

Oczywista Uwaga : zrób kopię zapasową swojego jeśli obawiasz się niezamierzonej utraty danych, spróbuj najpierw w środowisku przejściowym.

 70
Author: Stennie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:35

Jest to najprostsze zapytanie, którego użyłem na moim MongoDB 3.2

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

Zindeksuj swój customKey przed uruchomieniem, aby zwiększyć prędkość

 41
Author: Kanak Singhal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-19 07:44:40

Usuń duplikaty przez framework agregacji .

A. Jeśli chcesz usunąć za jednym razem.

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

B. możesz usuwać dokumenty jeden po drugim.

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
})
 26
Author: Somnath Muluk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-12 06:44:39

Podczas gdy @Stennie ' S jest poprawną odpowiedzią, nie jest to jedyny sposób. W rzeczywistości Podręcznik MongoDB prosi, abyś był bardzo ostrożny podczas robienia tego. Istnieją dwie inne opcje

  1. niech MongoDB zrobi to za Ciebie używając Map Reduce
  2. robisz programowo co jest mniej efektywne.
 8
Author: Aravind R. Yarram,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:15

Oto nieco bardziej "ręczny" sposób na zrobienie tego:

Zasadniczo najpierw uzyskaj listę wszystkich unikalnych kluczy, które Cię interesują.

Następnie wykonaj wyszukiwanie za pomocą każdego z tych klawiszy i usuń, jeśli wyszukiwanie zwróci większe niż jeden.

    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++
      })
    });
 1
Author: Fernando,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-23 12:51:15

Pip install mongo_remove_duplicate_indexes

  1. tworzenie skryptu w dowolnym języku
  2. iteruj nad swoją kolekcją
  3. Utwórz nową kolekcję i utwórz nowy indeks w tej kolekcji z unikalnym ustawieniem na true, pamiętaj ten indeks musi być taki sam jak indeks U chcesz usunąć duplikaty z oryginalnej kolekcji o tej samej nazwie dla ex-u mają kolekcję gier, a w tej kolekcji u mają pole gatunek, który zawiera duplikaty, które u chcą usunąć, więc po prostu utworzyć nowy kolekcja db.createCollection ("cname") utwórz nowy indeks db.cname.createIndex({'genre':1}, unikalnych:1) teraz, gdy u wstawi dokument o podobnym gatunku, tylko pierwszy zostanie zaakceptowany, inny zostanie odrzucony z błędem klucza duplicae
  4. Teraz wystarczy wstawić wartości formatu json u otrzymane do nowej kolekcji i obsłużyć wyjątek za pomocą obsługi wyjątków dla ex pymongo.błędy.DuplicateKeyError

Sprawdź kod źródłowy pakietu dla mongo_remove_duplicate_indexes dla lepszego zrozumienie

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-02 18:50:32

Jeśli masz wystarczająco dużo pamięci, możesz w Scali zrobić coś takiego:

cole.find().groupBy(_.customField).filter(_._2.size>1).map(_._2.tail).flatten.map(_.id)
.foreach(x=>cole.remove({id $eq x})
 0
Author: gilcu2,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-12 16:22:10