couchDBで多対多の関係を表す
-
10-07-2019 - |
質問
ログ分析アプリケーションを書いているとしましょう。メインドメインオブジェクトはLogEntryです。加えて。アプリケーションのユーザーは、関心のあるログエントリを記述するLogTopicを定義します。アプリケーションがログエントリを受信すると、それらをcouchDBに追加し、システム内のすべてのLogTopicsと照合して、トピックの基準に一致するかどうかを確認します。その場合、システムはエントリがトピックに一致することを記録する必要があります。したがって、LogEntriesとLogTopicsの間には多対多の関係があります。
これをRDBMSに保存している場合、次のようにします。
CREATE TABLE Entry (
id int,
...
)
CREATE TABLE Topic (
id int,
...
)
CREATE TABLE TopicEntryMap (
entry_id int,
topic_id int
)
CouchDBを使用して、最初に2つのドキュメントタイプのみを試しました。次のようなLogEntryタイプがあります:
{
'type': 'LogEntry',
'severity': 'DEBUG',
...
}
そしてLogTopicタイプがあり、次のようになります:
{
'type': 'LogTopic',
'matching_entries': ['log_entry_1','log_entry_12','log_entry_34',....],
...
}
各LogTopicドキュメントのmatching_entries
フィールドを使用してLogEntryドキュメントIDのリストを保存することで、関係を表すことがわかります。これはある程度うまくいきますが、複数のクライアントが両方ともトピックに一致するエントリを追加しようとすると問題が発生します。どちらも楽観的な更新を試みますが、1つは失敗します。現在使用しているソリューションは、RDBMSアプローチを本質的に再現し、次のような3番目のドキュメントタイプを追加することです。
{
'type':'LogTopicToLogEntryMap',
'topic_id':'topic_12',
'entry_id':'entry_15'
}
これは機能し、同時更新の問題を乗り越えますが、2つの予約があります:
- これを使用しているだけでは心配です それは私がやることだからです リレーショナルDB。あるのかな よりcouchDBに似た(リラックスできる?) 溶液。
- 私のビューはもうできません のすべてのエントリを取得する 1回の呼び出しで特定のトピック。俺の 以前のソリューションはそれを許可しました(私が include_docsパラメーターを使用しました)。
誰もが私にとってより良い解決策を持っていますか?使用しているビューも投稿すると役立ちますか?
解決
あなたのアプローチは問題ありません。 CouchDBを使用しても、リレーショナルモデリングを放棄するだけではありません。 2つのクエリを実行する必要がありますが、これは<!> quot; join <!> quot;であるためです。結合を含むSQLクエリも低速ですが、SQL構文を使用するとクエリを1つのステートメントで表現できます。
CouchDBでの数か月の経験で、これは私が発見したことです:
- スキーマがないため、アプリケーションモデルの設計は高速かつ柔軟です
- CRUDが存在するため、アプリケーションの開発は迅速かつ柔軟です
- さようならSQLインジェクション
- CouchDBでのSQL結合はもう少し作業が必要です
ニーズに応じて、couchdb-luceneはより複雑なクエリを作成するのにも役立つことがわかりました。
他のヒント
この質問を couchdbユーザーのメーリングリストとNathan Stott < href = "http://markmail.org/message/vsvwyz4rccc33jox" rel = "noreferrer">私を指して 非常に役立つブログ投稿、クリストファー・レンツ
リレーションを設定して、LogEntryが所属するLogTopicsを認識できるようにします。そうすれば、LogTopicsを変更する必要がないため、LogEntryを挿入しても競合が発生しません。
次に、単純なマップ関数は、属するLogTopicごとにLogEntryを1回発行し、基本的にその場でTopicEntryMapを構築します。
"map": function (doc) {
doc.topics.map(function (topic) {
emit(topic, doc);
});
}
この方法では、?key=<topic>
引数でビューをクエリすると、トピックに属するすべてのエントリが取得されます。