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