Добре запитання, я також розглядав це.
Створіть нову версію щодо кожної зміни
Я натрапив на модуль версії драйвера Mongoid для Ruby. Я сам його не використовував, але з того, що я міг знайти , він додає номер версії до кожного документа. Старіші версії вбудовані в сам документ. Основним недоліком є те, що весь документ дублюється при кожній зміні , що призведе до того, що під час роботи з великими документами зберігається багато повторюваного вмісту. Цей підхід чудово, хоча ви маєте справу з документами невеликого розміру та / або не оновлюєте документи дуже часто.
Зберігайте зміни лише в новій версії
Іншим підходом було б зберігання лише змінених полів у новій версії . Тоді ви можете «вирівняти» свою історію для реконструкції будь-якої версії документа. Це досить складно, оскільки вам потрібно відстежувати зміни у вашій моделі та зберігати оновлення та видалення таким чином, щоб ваша програма могла реконструювати оновлений документ. Це може бути складним, оскільки ви маєте справу зі структурованими документами, а не з плоскими таблицями 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 }
]
}
З кожним із цих підходів ви можете зберігати актуальну та вирівняну версію в одній колекції, а дані історії - в окремій колекції. Це має покращити час запитів, якщо вас цікавить лише остання версія документа. Але коли вам потрібні як остання версія, так і історичні дані, вам потрібно буде виконати два запити, а не один. Тож вибір використання однієї колекції порівняно з двома окремими колекціями повинен залежати від того, наскільки часто вашій програмі потрібні історичні версії .
Більшість цієї відповіді - це лише мозковий злив моїх думок, я ще нічого з цього не намагався. Озираючись на це, перший варіант, мабуть, є найпростішим та найкращим рішенням, якщо тільки накладні витрати на дублікати даних не дуже важливі для вашої програми. Другий варіант досить складний і, мабуть, не вартий зусиль. Третій варіант - це в основному оптимізація другого варіанту, який повинен бути простішим у здійсненні, але, ймовірно, не варто докладати зусиль із впровадження, якщо ви дійсно не можете скористатися варіантом перший.
З нетерпінням чекаю відгуків щодо цього та інших проблем вирішення проблеми :)