Каков наилучший способ сохранения документа с ревизиями в хранилище значений ключей? - PullRequest
2 голосов
/ 08 апреля 2011

Я новичок в магазинах Key-Value и мне нужна ваша рекомендация.Мы работаем над системой, которая управляет документами и их редакциями.Немного как вики.Мы думаем о сохранении этих данных в хранилище значений ключей.

Пожалуйста, не давайте мне рекомендации, какую базу данных вы предпочитаете, потому что мы хотим ее взломать, чтобы мы могли использовать множество различных баз данных значений ключей.Мы используем node.js, поэтому мы можем легко работать с json.

Мой вопрос: как должна выглядеть структура базы данных?У нас есть метаданные для каждого документа (метка времени, последний текст, id, latestrevision), и у нас есть данные для каждой ревизии (изменение, автор, метка времени и т. Д.).Итак, какую структуру ключ / значение вы рекомендуете?

thx

Ответы [ 3 ]

5 голосов
/ 09 апреля 2011

Извлечено из MongoDB групп . Это несколько специфично для MongoDB, однако, оно довольно общее.

Большинство этих реализаций истории разбиты на две общие стратегии.

Стратегия 1: вставлять историю

Теоретически вы можете встроить историю документа в сам документ. Это даже можно сделать атомарно.

> db.docs.save( { _id : 1, text : "Original Text" } ) 
> var doc = db.docs.findOne() 
> db.docs.update( {_id: doc._id}, { $set : { text : 'New Text' }, $push : { hist : doc.text } } ) 
> db.docs.find() 
{ "_id" : 1, "hist" : [ "Original Text" ], "text" : "New Text" } 

Стратегия 2: записать историю в отдельную коллекцию

> db.docs.save( { _id : 1, text : "Original Text" } ) 
> var doc = db.docs.findOne() 
> db.docs_hist.insert ( { orig_id : doc._id, ts : Math.round((new Date()).getTime() / 1000), data : doc } ) 
> db.docs.update( {_id:doc._id}, { $set : { text : 'New Text' }  } ) 

Здесь вы увидите, что я делаю две записи. Один в мастер-коллекцию и один в коллекцию истории. Чтобы получить быстрый просмотр истории, просто возьмите оригинальный идентификатор:

> db.docs_hist.ensureIndex( { orig_id : 1, ts : 1 }) 
> db.docs_hist.find( { orig_id : 1 } ).sort( { ts : -1 } )

  • Обе стратегии могут быть улучшены только отображением различий
  • Вы можете гибридизировать, добавив ссылку от history collection до original collection

Каков наилучший способ сохранения документа с ревизиями в хранилище значений ключей?

Трудно сказать, что есть "лучший способ". Очевидно, здесь есть некоторые компромиссы.

Встраивание:

  • атомные изменения в одном документе
  • может привести к большим документам, может нарушить разумные пределы размера
  • вероятно, придется улучшить код, чтобы избежать возврата полной истории, когда в этом нет необходимости

Отдельный сбор:

  • проще писать запросы
  • не атомарный, требуется две операции ( у вас есть транзакции? )
  • больше места для хранения ( дополнительные индексы в оригинальных документах )
1 голос
/ 04 февраля 2012

Я думаю, что есть несколько подходов, и этот вопрос старый, но я дам свои два цента, поскольку я работал над этим ранее в этом году.Я использовал MongoDB.

В моем случае у меня была учетная запись пользователя, которая затем имела профили в разных социальных сетях.Мы хотели отслеживать изменения в профилях социальных сетей и хотели пересмотреть их, поэтому мы создали две структуры для тестирования.Оба метода имеют объект User, который указывает на посторонние объекты.Мы не хотели вставлять объекты с самого начала.

Пользователь выглядел примерно так:

User {
  "tags"              : [Tags]
  "notes"             : "Notes"
  "facebook_profile"  : <combo_foreign_key>
  "linkedin_profile"  : <same as above>
}

, а затем для combo_foreign_key мы использовали этот шаблон (используя синтаксис Ruby для интерполяцииsimplicity)

combo_foreign_key = "#{User.key}__#{new_profile.last_updated_at}"

facebook_profiles {
  combo_foreign_key: facebook_profile
  ... and you keep adding your foreign objects in this pattern
}

Это дало нам O (1) поиск последнего FacebookProfile пользователя, но потребовало, чтобы мы сохранили последний FK, сохраненный в объекте User.Если бы мы хотели получить все профили FacebookProfiles, мы бы запросили все ключи в коллекции facebook_profiles с префиксом «# {User.key} __», и это было O (N) ...

Вторая стратегиямы пытались сохранить массив этих ключей FacebookProfile на объекте User, поэтому структура объекта User изменилась с

  "facebook_profile"  : <combo_foreign_key>

на

  "facebook_profile"  : [<combo_foreign_key>]

Здесь мы просто добавим кновый combo_key, когда мы добавили новый вариант профиля.Затем мы бы просто быстро отсортировали атрибут «facebook_profile» и проиндексировали самый большой из них, чтобы получить нашу последнюю копию профиля.Этот метод должен был отсортировать M строк и затем проиндексировать FacebookProfile на основе самого большого элемента в этом отсортированном списке.Немного медленнее захватывает последнюю копию, но это дает нам преимущество, зная каждую версию FacebookProfile Users одним махом, и нам не нужно беспокоиться о том, чтобы foreign_key действительно был последним объектом профиля.

Сначаланаши пересмотры были довольно малы, и они оба работали довольно хорошоЯ думаю, что сейчас предпочитаю первое, а не второе.

Хотелось бы услышать мнение других о том, как они решили эту проблему.Идея GIT, предложенная в другом ответе, на самом деле звучит для меня по-настоящему изящно, и для нашего варианта использования она вполне подойдет ... Круто.

1 голос
/ 08 апреля 2011

Я бы держал иерархию реальных данных под каждым документом с прикрепленными данными ревизии, например:

{ 
  [
    {
      "timestamp" : "2011040711350621",
      "data" : { ... the real data here .... }
    },
    {
      "timestamp" : "2011040711350716",
      "data" : { ... the real data here .... }
    }
  ]
}

Затем используйте операцию push для добавления новых версий и периодического удаления старых версий. Вы можете использовать последний (или первый) фильтр, чтобы получать только последнюю копию в любой момент времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...