Базы данных документов: избыточные данные, ссылки и т.д. (Специально для MongoDB)

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

Таким образом, простой ответ заключается в сохранении идентификатора пользователя в документе хранилища или в идентификаторе хранилища в пользовательском документе. Часто, однако, вы хотите получить доступ к 1-2 другим частям данных для показа, потому что Id не полезны. Например, имя клиента или имя магазина.

  • Как правило, вы сохраняете дубликат всего документа? Или просто хранить данные, которые вам нужны? Возможно, это зависит от размера документа и от того, сколько вам нужно.
  • Как вы справляетесь с тем, что у вас есть дубликаты данных? Вы собираетесь выслеживать данные, когда они меняются? Обновлять данные через некоторый интервал при загрузке? Только дублировать, когда вы можете предоставить устаревшие данные?

По достоинству оценит ваш вклад и/или ссылки на любые "лучшие практики" или, по крайней мере, на разумное обсуждение этих тем.

Ответ 1

В основном есть два сценария: свежий и устаревший.

Свежие данные

Сохранение дубликатов данных легко. Поддержание дублированных данных - сложная часть. Поэтому самое простое - избегать обслуживания, просто не сохраняя дубликатов данных. Это в основном полезно, если вам нужны свежие данные. Сохраняйте только ссылки и запрашивайте коллекции, когда вам нужно получить информацию.

В этом случае у вас будут дополнительные накладные расходы из-за дополнительных запросов. Альтернативой является отслеживание всех местоположений дублированных данных и обновление всех экземпляров при каждом обновлении. Это также связано с накладными расходами, особенно в отношениях N-to-M, подобных тем, которые вы упомянули. Таким образом, в любом случае у вас будут некоторые накладные расходы, если вам нужны свежие данные. Вы не можете иметь лучшее из обоих миров.

Данные устаревших

Если вы можете позволить себе иметь устаревшие данные, все становится намного проще. Чтобы избежать накладных расходов, вы можете хранить дубликаты данных. Чтобы избежать дублирования данных, вы не собираетесь хранить дубликаты данных. По крайней мере, не активно.

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

Резюме

Сохранять ссылки только на другие документы. Если вы можете позволить себе использовать устаревшие данные, используйте периодические задания уменьшения масштаба для генерации повторяющихся данных. Избегайте дублирования данных; он сложный и подверженный ошибкам.

Ответ 2

Ответ здесь действительно зависит от того, насколько текущим вам нужны ваши данные.

@Niels имеет хорошее резюме здесь, но я считаю справедливым отметить, что вы можете "обмануть".

Скажем, что вы хотите отображать магазины, используемые пользователем. Очевидная проблема здесь заключается в том, что вы не можете "встраивать" Store внутри пользователя b/c, поскольку магазин слишком важен сам по себе. Но что вы можете сделать, это вставить некоторые данные Store в User.

Просто используйте материал, который хотите отобразить, например "Store Name". Таким образом, ваш объект User будет выглядеть так:

{
  _id : MongoID(),
  name : "Testy Tester",
  stores : [ 
             { _id : MongoID(), "name" : 'Safeway' },
             { _id : MongoID(), "name" : 'Walmart' },
             { _id : MongoID(), "name" : 'Best Buy' }
            ]
}

Таким образом вы можете отобразить типичное представление "сетки", но для получения дополнительных данных о хранилище требуется ссылка.

Ответ 3

Чтобы ответить на ваши прямые вопросы:

  • Нет дубликатов.
  • Нет дубликатов.

;)

Единственными дубликатами, которые вы должны иметь, являются "простые" значения, такие как вес (которые могут оказаться одинаковыми, но не более эффективны ни в одном времени, ни в пространстве для хранения отдельно), а также идентификаторы, ссылающиеся на другой объект (который являются дублирующими значениями, но гораздо меньшими и более управляемыми, чем дублирующиеся данные объекта, которые они заменяют).

Теперь, чтобы ответить на ваш сценарий: то, что вы хотите, является отношением "многие ко многим". Обычным решением здесь является создание третьей "сквозной" или "мостовой" таблицы/коллекции, которая, вероятно, называется StoreUsers:

StoreUsers
----------
storeuser_id
store_id
user_id

Вы добавляете к ней запись для каждой ссылки между магазинами и пользователями, будь то для другого магазина, другого пользователя или нескольких пользователей в одном магазине. Затем вы можете просмотреть это самостоятельно независимо от магазина или пользователя. MongoDB также поддерживает этот подход; это не специфично для РСУБД.