回答:
クエリのニーズに応じて、ユーザードキュメントにすべてを入れることができます。
{name:"Joe"
,roles:["Admin","User","Engineer"]
}
すべてのエンジニアを取得するには、以下を使用します。
db.things.find( { roles : "Engineer" } );
別のドキュメントでロールを維持する場合は、名前の代わりにドキュメントの_idをロール配列に含めることができます。
{name:"Joe"
,roles:["4b5783300334000000000aa9","5783300334000000000aa943","6c6793300334001000000006"]
}
次のような役割を設定します。
{_id:"6c6793300334001000000006"
,rolename:"Engineer"
}
RDBMSに関する長年の経験に基づいてモデル化を試みる代わりに、アトミックを考慮しながら、読み取りのユースケースを最適化することで、MongoDB、Redis、およびその他のNoSQLデータストアを使用してドキュメントリポジトリソリューションをモデル化する方がはるかに簡単であることがわかりました書き込みユースケースでサポートする必要がある書き込み操作。
たとえば、「Users in Roles」ドメインの使用法は次のとおりです。
これは、次のドキュメントテンプレートとしてモデル化できます。
User: { _id: UniqueId, name: string, roles: string[] }
Indexes: unique: [ name ]
Role: { _id: UniqueId, name: string, users: string[] }
Indexes: unique: [ name ]
UserエンティティのRole関連の機能などの高頻度の使用をサポートするために、User.Rolesは意図的に非正規化され、UserとRole.Usersに重複して保存されます。
テキストではすぐにはわからないが、これがドキュメントリポジトリを使用するときに推奨されるタイプの考え方である場合。
これにより、操作の読み取り側に関するギャップを埋めることができます。
書き込み側では、アトミックな書き込みに従ってモデル化することが推奨されます。たとえば、ドキュメント構造がロックを取得し、1つのドキュメントを更新し、次に別のドキュメントを更新し、場合によってはさらに多くのドキュメントを更新し、ロックを解放する必要がある場合、モデルが失敗した可能性があります。分散ロックを構築できるからといって、それらを使用することになっているわけではありません。
ロール内のユーザーモデルの場合、ロックのアトミックな書き込み回避を拡張する操作は、ロールからユーザーを追加または削除することです。どちらの場合も、操作が成功すると、単一のユーザーと単一のロール文書の両方が更新されます。何かが失敗した場合、クリーンアップを実行するのは簡単です。これは、ドキュメントリポジトリが使用される作業ユニットパターンがかなり多く登場する1つの理由です。
ロックのアトミックな書き込み回避を実際に拡張する操作はRoleをクリアすることであり、User.roles配列からRole.nameを削除するために多くのユーザー更新が発生します。この場合、このクリア操作は通常推奨されませんが、必要に応じて、操作を注文することで実装できます。
手順2で発生する可能性が最も高い問題の場合、手順1と同じユーザー名のセットを使用して回復または続行できるため、ロールバックは簡単です。
私はこの質問に出くわしました。古い質問ですが、回答に記載されていない可能性をいくつか追加すると便利だと思いました。また、ここ数年で状況は少し変化しているため、SQLとNoSQLが互いに近づいていることを強調する価値があります。
コメンターの一人は、「データがリレーショナルである場合はリレーショナルを使用する」という賢明な注意姿勢を示しました。ただし、そのコメントは、スキーマが常にアプリケーションの前にあるリレーショナルの世界でのみ意味があります。
RELATIONAL WORLD:Structure data> Write application to get it
NOSQL WORLD:Design application> Structure dataそれに応じて
データがリレーショナルであっても、NoSQLはオプションです。たとえば、1 対多の関係はまったく問題なく、MongoDBのドキュメントで広くカバーされています
この質問が投稿されて以来、noSQLをSQLに近づけようとする深刻な試みがありました。カリフォルニア大学サンディエゴ校のYannis Papakonstantinou率いるチームは、SQL ++の実装であるFORWARDに取り組んでいます。これは、ここに掲載されているような永続的な問題の解決策となる可能性があります。
より実用的なレベルでは、Couchbase 4.0のリリースにより、初めてNoSQLでネイティブJOINを実行できるようになりました。彼らは独自のN1QLを使用します。これはJOIN
彼らのチュートリアルからの例です:
SELECT usr.personal_details, orders
FROM users_with_orders usr
USE KEYS "Elinor_33313792"
JOIN orders_with_users orders
ON KEYS ARRAY s.order_id FOR s IN usr.shipped_order_history END
N1QLは、集約、フィルタリングなど、すべてではないにしてもほとんどのSQL操作を可能にします。
それでもMongoDBが唯一のオプションである場合は、アプリケーションがデータの構造よりも優先される必要があるという私の考えに戻りたいと思います。いずれの回答もハイブリッド埋め込みについて言及していないため、ほとんどのクエリされたデータはドキュメント/オブジェクトに埋め込まれ、参照は少数のケースで保持されます。
例:情報(ロール名以外)は待機できますか?ユーザーがまだ必要としないものを要求しないことで、アプリケーションのブートストラップはより速くなるでしょうか?
これは、ユーザーがログインし、ユーザーが所属するすべてのロールのすべてのオプションを表示する必要がある場合に当てはまります。ただし、ユーザーは「エンジニア」であり、このロールのオプションはほとんど使用されません。つまり、エンジニアは、エンジニアがオプションをクリックしたい場合に備えて、オプションを表示するだけで済みます。
これは、最初にアプリケーションに(1)ユーザーが属するロールと(2)特定のロールにリンクされたイベントに関する情報を取得する場所を通知するドキュメントで実現できます。
{_id: ObjectID(),
roles: [[“Engineer”, “ObjectId()”],
[“Administrator”, “ObjectId()”]]
}
または、さらに良いのは、ロールコレクションのrole.nameフィールドにインデックスを付けることで、ObjectID()を埋め込む必要がない場合もあります。
別の例:常に要求されるすべての役割に関する情報はありますか?
また、ユーザーがダッシュボードにログインし、90%の時間が「エンジニア」ロールにリンクされたタスクを実行する場合もあります。ハイブリッド埋め込みは、その特定の役割に対して完全に実行され、残りの参照のみを保持します。
{_id: ObjectID(),
roles: [{name: “Engineer”,
property1: value1,
property2: value2
},
[“Administrator”, “ObjectId()”]
]
}
スキーマレスであることは、NoSQLの特性だけではなく、この場合の利点にもなります。ユーザーオブジェクトの「Roles」プロパティに異なるタイプのオブジェクトをネストすることは完全に有効です。
従業員と会社がエンティティオブジェクトの 場合は、次のスキーマを使用してください。
employee{
//put your contract to employee
contracts:{ item1, item2, item3,...}
}
company{
//and duplicate it in company
contracts:{ item1, item2, item3,...}
}