web-dev-qa-db-ja.com

Mongodbのキーに基づいて重複を削除する方法は?

MongoDBにはコレクションがあります(約300万件のレコード)。サンプルレコードは次のようになります。

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

同じsource_references.keyを持つコレクションに重複したレコードがたくさんあります。 (重複によって、source_references.keyではなく_id)。

source_references.keyに基づいて重複するレコードを削除したいので、各レコードをトラバースし、存在する場合はレコードを削除するコードをいくつかPHP)と書くことを考えています。

Mongo Internalコマンドラインで重複を削除する方法はありますか?

49
user1518659

source_references.keyが重複レコードを識別することが確実な場合は、MongoDB 2.6以前の dropDups:true インデックス作成オプションで一意のインデックスを確認できます。

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

これにより、各source_references.key値に対して最初の一意のドキュメントが保持され、重複キー違反の原因となる後続のドキュメントは削除されます。

重要な注意事項

  • dropDupsオプションは MongoDB 3.0で削除 であったため、別のアプローチが必要になります。たとえば、次のように提案された集約を使用できます。 一意のキーを追加した後でもMongoDBがドキュメントを複製する .
  • source_references.keyフィールドが欠落しているドキュメントは、null値を持つと見なされるため、キーフィールドが欠落している後続のドキュメントは削除されます。 sparse:true インデックス作成オプションを追加して、source_references.keyフィールドを持つドキュメントにのみインデックスが適用されるようにすることができます。

明らかな注意:データベースのバックアップを取り、意図しないデータ損失が心配な場合は、まずステージング環境でこれを試してください。

76
Stennie

これは、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にインデックスを付けて速度を上げます

52
Kanak Singhal

@ Stennie'sは有効な答えですが、それが唯一の方法ではありません。実際、MongoDBマニュアルでは、その際に非常に慎重になるように求められています。他に2つのオプションがあります

  1. MongoDBにそれを行わせてください Map Reduceを使用
  2. プログラムで を実行しますが、これは効率的ではありません。
8

以下に、もう少し「手動」で行う方法を示します。

基本的に、まず、興味のあるすべての一意のキーのリストを取得します。

次に、これらの各キーを使用して検索を実行し、その検索が1より大きい値を返す場合は削除します。

    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++
      })
    });
2
Fernando

pip install mongo_remove_duplicate_indexes

  1. 任意の言語でスクリプトを作成します
  2. コレクションを反復処理する
  3. 新しいコレクションを作成し、一意のtrueに設定してこのコレクションに新しいインデックスを作成します。このインデックスは、元のコレクションの重複を削除するインデックスuと同じである必要があります。コレクションuには重複を含むフィールドジャンルがあり、削除したいので、新しいコレクションを作成しますdb.createCollection( "cname")新しいインデックスを作成しますdb.cname.createIndex({'genre':1}、unique:1)now uが類似のジャンルのドキュメントを最初に挿入するときのみ受け入れられ、他は重複キーエラーで拒否されます
  4. 受信したjson形式の値を新しいコレクションに挿入し、ex pymongo.errors.DuplicateKeyErrorの例外処理を使用して例外を処理するようになりました

理解を深めるために、mongo_remove_duplicate_indexesのパッケージソースコードを確認してください。

0
user7106300

十分なメモリがある場合は、scalaで次のようなことができます。

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