MongoDBでは、一意のインデックスにより、フィールド内の特定の値が複数のドキュメントに存在しないことが保証されます。 しない 値が単一のドキュメント内の配列全体で一意であることを保証します。これについては、MongoDBマニュアルで説明されており、一意のマルチキーインデックスについて説明しています。
したがって、一意のインデックスは要件を満たしません。個別のドキュメントに重複する組み合わせが含まれるのを防ぎますが、単一のドキュメントに配列全体で重複する値を含めることはできます。
最善のオプションは、technologyEmployeeRefオブジェクトの配列を個別のドキュメントに分割するようにデータモデルを変更することです。個別のドキュメントに分割すると、一意のインデックスを使用して一意性を強制できます。
このデータモデルの変更に必要な特定の実装は、アクセスパターンによって異なります(これはこの質問の範囲外です)。
これを行うことができるそのような方法の1つは、technologyEmployeeRef配列に現在存在するすべてのフィールドを持つTechnologyEmployeeコレクションを作成することです。さらに、このTechnologyEmployeeコレクションには、電子メールなどのフィールドがあり、これを使用して、このコレクションをEmployeeコレクション内のドキュメントに関連付けることができます。
サンプルの従業員ドキュメント
{
....
....
"firstName" : "John",
"lastName" : "Doe",
"email" : "[email protected]",
.....
.....
.....
}
EmployeeTechnologyドキュメントのサンプル
{
"email" : "[email protected]",
"technologyCd" : "Java",
"technologyName" : "Java8",
....
.....
"status" : "A"
}
EmployeeTechnologyコレクションのインデックス
{'email' : 1, 'technologyCd' : 1}, {unique: true}
このアプローチの欠点は、すべてのデータを取得するために2つのコレクションから読み取る必要があることです。両方のコレクションから同時にデータを取得する必要がほとんどない場合、この欠点は大きな問題にはならない可能性があります。すべてのデータが必要な場合は、インデックスを使用することでデータを高速化できます。インデックスを使用すると、対象となるクエリを使用することでさらに高速化できます。
もう1つのオプションは、データを非正規化することです。これを行うには、テクノロジーデータと同時にアクセスする必要のある従業員データを複製します。
サンプルドキュメント
[
{
....
"firstName" : "John",
"lastName" : "Doe",
"email" : "[email protected]",
.....
"technologyCd" : "Java",
"technologyName" : "Java8",
....
"status" : "A"
},
{
....
"firstName" : "John",
"lastName" : "Doe",
"email" : "[email protected]",
.....
"technologyCd" : "Spring",
"technologyName" : "Spring Boot2",
....
"status" : "A"
}
]
このMongoDBブログ投稿では、彼らは次のように述べています
これは、頻繁に読み取られ、更新されるよりもはるかに頻繁に読み取られ、非正規化された値の更新は遅く、費用がかかり、アトミックではないため、強一貫性を必要としないフィールドに対してのみ行います。
または、すでに述べたように、データモデルをそのままにして、アプリケーション側で一意性のチェックを実行するのが理にかなっている場合があります。これにより、最高の読み取りパフォーマンスが得られる可能性がありますが、いくつかの欠点があります。まず、アプリケーションがデータベースを更新する前にいくつかのチェックを実行する必要があるため、書き込み操作が遅くなります。
可能性は低いかもしれませんが、それでも重複してしまう可能性もあります。同じEmployeeTechnologyオブジェクトを配列に挿入する2つの連続した要求がある場合、最初の要求がデータベースに書き込まれる前に、2番目の要求の検証が終了(および合格)する場合があります。私が取り組んだアプリケーションで、私自身も同様のシナリオを見てきました。アプリケーションが一意性をチェックしていても、ユーザーが送信ボタンをダブルクリックすると、データベースに重複したエントリが存在することになります。この場合、最初のクリックでボタンを無効にすると、リスクが大幅に減少しました。要件と重複エントリの影響によっては、この小さなリスクは許容できる場合があります。
どのアプローチが最も理にかなっているのかは、アクセスパターンと要件に大きく依存します。これがお役に立てば幸いです。