始めに
MongoDBを利用している際に、重複したデータを複数一括で削除する必要があったので、その際に実行したクエリを共有します。やりたいことは単純だったのですが、ドキュメントがあまりなくクエリ構築に悩んだので備忘録として残しておきます。
MongoDBのデータ操作コマンドに関しては、以下のリンクを参照。
Database Commands — MongoDB Manual
実行
前準備
MongoDBに、以下のようにusername
に同じ値を持つユーザが複数登録されてしまっている。この状態の際に、username
で重複するデータを削除したい。
> db.user.find()
{ _id: ObjectId("619b2dfa75ca1af74dbe6d8d"),
username: 'taro',
age: 18 }
{ _id: ObjectId("619b2e0275ca1af74dbe6d8f"),
username: 'taro',
age: 18 }
{ _id: ObjectId("619b2e1175ca1af74dbe6d91"),
username: 'saburo',
age: 22 }
{ _id: ObjectId("619b2e1875ca1af74dbe6d93"),
username: 'saburo',
age: 22 }
{ _id: ObjectId("619b2e1c75ca1af74dbe6d95"),
username: 'saburo',
age: 22 }
{ _id: ObjectId("619b2e2e75ca1af74dbe6d97"),
username: 'siro',
age: 25 }
重複削除のコマンド
username
要素の重複を削除する場合、以下のコマンドを実行する。
> db.user.aggregate([
{ $group:
{
_id: "$username",
dups: { "$addToSet": "$_id" },
count: { "$sum": 1 }
}
},
{ $match:
{
count: { "$gt": 1 }
}
}
]).forEach(function(doc) {
doc.dups.shift();
db.user.remove({_id : {$in: doc.dups }});
})
実行後再度確認すると、重複が削除されていることが確認できる。
> db.user.find()
{ _id: ObjectId("619b2dfa75ca1af74dbe6d8d"),
username: 'taro',
age: 18 }
{ _id: ObjectId("619b2e1875ca1af74dbe6d93"),
username: 'saburo',
age: 22 }
{ _id: ObjectId("619b2e2e75ca1af74dbe6d97"),
username: 'siro',
age: 25 }
クエリの解説
先ほど実行したクエリの各要素の意味は以下の通り。
> db.user.aggregate([
{ $group: # 同じusernameを持つものでグループ化
{
_id: "$username", # ここに重複を集約したいキーを指定する
dups: { "$addToSet": "$_id" }, # dupsと言う辞書に重複が発生した_idを格納する。
count: { "$sum": 1 } # usernameの出現回数をカウント
}
},
{ $match: # 上記のクエリで集約した結果に対して条件に合うもののみを抽出
{
count: { "$gt": 1 } # countが2以上(=重複が存在するもの)のみ抽出
}
}
]).forEach(function(doc) {
doc.dups.shift(); # 重複が存在するキーのうち、先頭1つ残すために、先頭の要素を削除対象から除外
db.user.remove({_id : {$in: doc.dups }}); # キーの配列より一致する_idを持つ要素を削除
})