Хороший вопрос, я тоже этим занимался.
Создавать новую версию при каждом изменении
Я наткнулся на модуль управления версиями драйвера 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 }
]
}
С помощью каждого из этих подходов вы можете хранить актуальную и упорядоченную версию в одной коллекции, а данные истории - в отдельной коллекции. Это должно сократить время запроса, если вас интересует только последняя версия документа. Но когда вам нужна как последняя версия, так и исторические данные, вам нужно будет выполнить два запроса, а не один. Таким образом, выбор использования одной коллекции или двух отдельных коллекций должен зависеть от того, как часто вашему приложению нужны исторические версии .
По большей части этот ответ - всего лишь свалка моих мыслей, я еще ничего из этого не пробовал. Оглядываясь назад, можно сказать, что первый вариант, вероятно, является самым простым и лучшим решением, если только накладные расходы на дублирование данных не очень значительны для вашего приложения. Второй вариант довольно сложен и, вероятно, не стоит усилий. Третий вариант в основном является оптимизацией второго варианта и должен быть проще в реализации, но, вероятно, не стоит усилий по реализации, если только вы действительно не можете выбрать вариант один.
Жду отзывов по этому поводу и других решений проблемы :)