MongoDBで複合ユニークインデックスを使って複数フィールドの重複データ登録を防ぐ方法
MongoDBで複数フィールドの組み合わせが重複しないようにするには
MongoDBでは、単一フィールドだけでなく「複数のフィールドの組み合わせ」に対しても一意性(ユニーク)制約を持たせることができます。これを実現するのが複合インデックスに unique: true オプションを付けた複合ユニークインデックスです。
インデックス作成には ensureIndex() メソッドを使用し、オプションに {unique:true} を指定します。なお、新しいバージョンのMongoDBでは ensureIndex() は非推奨となっており、代わりに同じ構文で使える createIndex() の使用が推奨されています。
それでは、実際にコレクションを作成し、動作を確認していきましょう。
1. 複合ユニークインデックスを作成する
ここでは「FirstName(名前)」と「Subject(科目)」の2つのフィールドの組み合わせが重複しないようにインデックスを作成します。
> db.demo272.ensureIndex({"FirstName":1,"Subject":1},{unique:true});
{
"createdCollectionAutomatically" : true,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}コレクションが自動的に作成され、インデックスが追加されたことがわかります。
2. ドキュメントを挿入して動作を確認する
まずは通常どおりドキュメントを挿入してみます。
> db.demo272.insertOne({"FirstName":"Chris","Subject":"MySQL"});
{
"acknowledged" : true,
"insertedId" : ObjectId("5e48232a1627c0c63e7dbabf")
}
> db.demo272.insertOne({"FirstName":"Chris","Subject":"MongoDB"});
{
"acknowledged" : true,
"insertedId" : ObjectId("5e48232f1627c0c63e7dbac0")
}
> db.demo272.insertOne({"FirstName":"David","Subject":"MySQL"});
{
"acknowledged" : true,
"insertedId" : ObjectId("5e48233a1627c0c63e7dbac1")
}上記の3件は、「FirstName」と「Subject」の組み合わせがそれぞれ異なるため、問題なく挿入できます。たとえば「Chris + MySQL」「Chris + MongoDB」のように、片方のフィールドが同じでも、もう片方が異なれば重複とはみなされません。
3. 重複データを挿入するとどうなるか
次に、すでに存在する「Chris + MySQL」の組み合わせと完全に一致するドキュメントを挿入してみます。
> db.demo272.insertOne({"FirstName":"Chris","Subject":"MySQL"});
2020-02-15T22:28:55.137+0530 E QUERY [js] WriteError: E11000 duplicate key error collection: test.demo272 index: FirstName_1_Subject_1 dup key: { : "Chris", : "MySQL" } :
WriteError({
"index" : 0,
"code" : 11000,
"errmsg" : "E11000 duplicate key error collection: test.demo272 index: FirstName_1_Subject_1 dup key: { : \"Chris\", : \"MySQL\" }",
"op" : {
"_id" : ObjectId("5e48234f1627c0c63e7dbac2"),
"FirstName" : "Chris",
"Subject" : "MySQL"
}
})
WriteError@src/mongo/shell/bulk_api.js:461:48
Bulk/mergeBatchResults@src/mongo/shell/bulk_api.js:841:49
Bulk/executeBatch@src/mongo/shell/bulk_api.js:906:13
Bulk/this.execute@src/mongo/shell/bulk_api.js:1150:21
DBCollection.prototype.insertOne@src/mongo/shell/crud_api.js:252:9
@(shell):1:1このように、E11000 duplicate key error(重複キーエラー)が発生し、挿入が拒否されます。エラーメッセージには、違反したインデックス名(FirstName_1_Subject_1)と重複したキーの値が表示されるため、原因を特定しやすくなっています。
4. 登録済みドキュメントを確認する
find() メソッドを使って、コレクション内のすべてのドキュメントを表示してみましょう。
> db.demo272.find();
実行結果は以下のとおりです。
{ "_id" : ObjectId("5e48232a1627c0c63e7dbabf"), "FirstName" : "Chris", "Subject" : "MySQL" }
{ "_id" : ObjectId("5e48232f1627c0c63e7dbac0"), "FirstName" : "Chris", "Subject" : "MongoDB" }
{ "_id" : ObjectId("5e48233a1627c0c63e7dbac1"), "FirstName" : "David", "Subject" : "MySQL" }重複しようとした4件目のドキュメントは登録されておらず、最初の3件だけが保存されていることが確認できます。
まとめ
ensureIndex()(新バージョンではcreateIndex())に{unique:true}を指定することで、複数フィールドの組み合わせに対する一意制約を設定できる。- 単一フィールドだけが同じでも、他のフィールドが異なれば重複とは判定されない。
- 制約に違反する挿入を行うと、E11000 duplicate key error が発生し、データは登録されない。
この仕組みを活用すれば、ユーザー名とメールアドレスの組み合わせなど、ビジネスロジック上「重複させたくないデータ」をデータベースレベルで確実に防ぐことができます。
-
MongoDBで複数フィールドの存在を確認するクエリの書き方($existsと$andの活用)
MongoDBで複数のフィールドの存在を確認する方法MongoDBでは、ドキュメント内に特定の複数のフィールドがすべて存在するかどうかを確認したいケースがよくあります。そのような場合には、$exists 演算子と $and 演算子を組み合わせて使用します。この記事では、実際にコレクションを作成しながら、複数フィールドの存在をチェックするクエリの書き方を具体的に解説します。1. サンプルコレクションとドキュメントの作成まず、insertOne() メソッドを使って、コレクション demo475 にドキュメントを挿入していきます。> db.demo475.insertOne({Student
-
MongoDBの集計パイプラインで複数フィールドをカウントする方法($facet活用)
MongoDBで複数のフィールドごとにドキュメントをカウントしたい場合、$facet演算子を使うのが効果的です。$facetは、同じ入力ドキュメント群に対して、単一のステージ内で複数の集計パイプラインを同時に処理できる強力な機能です。この記事では、実際にコレクションを作成し、$facetを組み合わせた集計クエリで複数フィールドの値をカウントする手順を解説します。1. サンプルコレクションの作成まず、insertOne()メソッドを使ってサンプルドキュメントを挿入します。各ドキュメントにはdetails1・details2・details3という3つのネストされたフィールドを持たせます。>