良い質問です。私もこれを調べていました。
変更ごとに新しいバージョンを作成する
RubyのMongoidドライバーのバージョン管理モジュールに出くわしました。私自身は使用していませんが、見つけたものから、各ドキュメントにバージョン番号を追加しています。古いバージョンはドキュメント自体に埋め込まれています。主な欠点は、変更のたびにドキュメント全体が複製されるため、大きなドキュメントを処理しているときに、大量の重複コンテンツが保存されることになります。このアプローチは、小さいサイズのドキュメントを処理している場合や、ドキュメントを頻繁に更新しない場合に適しています。
変更を新しいバージョンにのみ保存する
別のアプローチは、変更されたフィールドのみを新しいバージョンに格納することです。次に、履歴を「フラット化」して、ドキュメントの任意のバージョンを再構築できます。ただし、アプリケーションが最新のドキュメントを再構築できるようにモデルの変更を追跡し、更新と削除を保存する必要があるため、これはかなり複雑です。フラットなSQLテーブルではなく構造化されたドキュメントを扱うので、これは難しいかもしれません。
変更をドキュメント内に保存する
各フィールドは、個別の履歴を持つこともできます。この方法では、ドキュメントを特定のバージョンに再構築する方がはるかに簡単です。アプリケーションでは、変更を明示的に追跡する必要はありませんが、値を変更したときにプロパティの新しいバージョンを作成するだけです。ドキュメントは次のようになります。
{
_id: "4c6b9456f61f000000007ba6"
title: [
{ version: 1, value: "Hello world" },
{ version: 6, value: "Foo" }
],
body: [
{ version: 1, value: "Is this thing on?" },
{ version: 2, value: "What should I write?" },
{ version: 6, value: "This is the new body" }
],
tags: [
{ version: 1, value: [ "test", "trivial" ] },
{ version: 6, value: [ "foo", "test" ] }
],
comments: [
{
author: "joe", // Unversioned field
body: [
{ version: 3, value: "Something cool" }
]
},
{
author: "xxx",
body: [
{ version: 4, value: "Spam" },
{ version: 5, deleted: true }
]
},
{
author: "jim",
body: [
{ version: 7, value: "Not bad" },
{ version: 8, value: "Not bad at all" }
]
}
]
}
ただし、バージョンでドキュメントの一部に削除済みのマークを付けるのは、やや厄介です。state
アプリケーションから削除/復元できるパーツのフィールドを導入できます。
{
author: "xxx",
body: [
{ version: 4, value: "Spam" }
],
state: [
{ version: 4, deleted: false },
{ version: 5, deleted: true }
]
}
これらのアプローチのそれぞれを使用して、最新のフラット化されたバージョンを1つのコレクションに保存し、履歴データを別のコレクションに保存できます。ドキュメントの最新バージョンのみに関心がある場合、これによりクエリ時間が改善されます。ただし、最新バージョンと履歴データの両方が必要な場合は、1つではなく2つのクエリを実行する必要があります。したがって、単一のコレクションを使用するか、2つの別個のコレクションを使用するかの選択は、アプリケーションが履歴バージョンを必要とする頻度に依存するはずです。
この答えの大部分は私の考えの頭脳のダンプです。私は実際にこれをまだ試していません。振り返ってみると、重複データのオーバーヘッドがアプリケーションにとって非常に重要でない限り、最初のオプションがおそらく最も簡単で最良のソリューションです。2番目のオプションは非常に複雑で、おそらく努力する価値はありません。3番目のオプションは基本的にオプション2の最適化であり、実装が容易ですが、実際にオプション1で実行できない場合を除いて、実装する価値はありません。
これに関するフィードバック、および問題に対する他の人々の解決策を楽しみにしています:)