Этот вопрос предназначен для всех экспертов NoSQL и специально mongoDB. Я начал с разработки реляционной БД для проекта, но клиент хочет, чтобы мы использовали БД, которая может легко масштабироваться. Для этого мы решили использовать mongoDB. В эти дни мне сложно сопоставить мою реляционную модель для NoSQL. У меня есть таблица пользователей, которая имеет отношение «многие ко многим» с множеством других таблиц, как показано ниже:
У меня есть несколько вариантов при конвертации для mongoDB:
Вариант 1 (с полными рядами пользователей):
users:{ _id:<user_id>, battles:{[battle1, battle2, ...]}, items:{[item1, item2, ...]}, locations:{[location1, location2, ...]}, units:{[unit1, unit2, ...]}, } battles:{ <battle_info> } locations:{ <location_info> } units:{ <units_info> } items:{ <items_info> }
Option2 (только с внешними ключами у пользователей):
users:{ _id:<user_id>, battles:{[battle1_id, battle2_id, ...]}, items:{[item1_id, item2_id, ...]}, locations:{[location1_id, location2_id, ...]}, units:{[unit1_id, unit2_id, ...]}, } battles:{ <battle_info> } locations:{ <location_info> } units:{ <units_info> } items:{ <items_info> }
Вариант 3 (идентификаторы пользователей в других таблицах):
users:{ _id:<user_id>, } battles:{ <battle_info>, user:{[user1_id, user2_id, ...]} } locations:{ <location_info>, user:{[user1_id, user2_id, ...]} } units:{ <units_info>, user:{[user1_id, user2_id, ...]} } items:{ <items_info>, user:{[user1_id, user2_id, ...]} }
Вариант 1 имеет много дубликатов, поскольку мы добавляем полные строки других таблиц. Одна из проблем, которые я вижу в этом, заключается в том, что если обновляется определенный предмет или битва, нам нужно будет найти все его в таблице пользователей и обновить их. Но это дает нам преимущество всегда иметь полный объект пользователей, который может быть передан клиентскому приложению во время входа в систему.
Вариант 2 более реляционный, где мы имеем только mongoIds других таблиц в таблице users. Преимущество этих опций заключается в том, что обновление битвы или элемента не имеет большой стоимости, поскольку ссылки на строки не копируются. С другой стороны, когда пользователь входит в систему, нам нужно будет найти все ссылочные единицы, сражения, предметы и местоположения, чтобы отвечать на полный объект пользователей.
Вариант 3 противоположно варианту 2, где таблицы mongoIds of users хранятся в других таблицах. Этот вариант мне не очень нравится.
Я бы очень признателен, если кто-то может вести меня или придумать лучшую модель.
Редактировать:
В основном это игра MMORPG, в которой приложения для нескольких клиентов будут подключаться к серверу через веб-службы. У нас есть локальный db на клиенте для хранения данных. Я хочу модель, через которую сервер может отвечать полным пользовательским объектом, а затем обновлять или вставлять данные, измененные в клиентских приложениях.
Во-первых, NoSQL не один размер подходит всем. В SQL почти так же моделируется почти каждое отношение 1: N и M: N. Философия NoSQL заключается в том, что способ моделирования данных зависит от данных и их шаблонов использования.
Во-вторых, я согласен с Марком Бейкером: Масштабирование тяжело, и это достигается за счет ослабления ограничений. Это не вопрос технологии. Мне нравится работать с MongoDB, но по другим причинам (нет необходимости кодировать уродливый SQL, нет необходимости в сложной, раздутой ORM и т. Д.),
Теперь давайте рассмотрим ваши варианты: Вариант 1 копирует больше данных, чем необходимо. Вам часто придется денормализовать некоторые данные, но никогда не все. Если это так, дешевле получить ссылочный объект.
Вариант 2/3 они очень похожи. Ключ здесь: кто пишет? Вы не хотите, чтобы многие клиенты имели доступ на запись к тому же документу, потому что это заставит вас использовать механизм блокировки и / или ограничиться только действиями модификатора. Поэтому вариант 2, вероятно, лучше 3. Однако, если A атакует B, они также инициируют запись пользователю B, поэтому вы должны быть уверены, что ваши записи безопасны.
Вариант 4 Частичная денормализация: ваш пользовательский объект кажется наиболее важным, поэтому как насчет этого:
user { battles : [ {"Name" : "The battle of foo", "Id" : 4354 }, ... ] ... }
Это упростит отображение, например, пользовательской панели, потому что вам не нужно знать все детали на панели управления. Примечание: структура данных затем связана с деталями презентации.
Вариант 5 Данные по краям. Зачастую отношение должно также содержать данные:
user { battles : [ {"Name" : "The battle of foo", "unitsLost" : 54, "Id" : 34354 }, ... ] }
здесь unitsLost
специфичен для пользователя и битвы, поэтому данные находятся на краю графика. В отличие от имени битвы, эти данные не денормализуются.
Вариант 6 Коллекции компоновщиков. Конечно, такие «краевые данные» могут расти огромно и даже могут потребовать отдельную коллекцию (сборщик ссылок). Это полностью устраняет проблему блокировок доступа:
user { "_id" : 3443 } userBattles { userId : 3443, battleId : 4354, unitsLost : 43, itemsWon : [ <some list > ], // much more data }
Какой из них лучше всего зависит от множества деталей вашего приложения. Если пользователи делают много кликов (т. Е. У вас есть мелкозернистый интерфейс), имеет смысл разделить объекты, как в вариантах 4 или 6. Если вам действительно нужны все данные в одной партии, частичная денормализация не помогает, поэтому вариант 2 был бы предпочтительнее. Имейте в виду проблему с несколькими авторами.
Вариант 2 – это путь.
Если вы сделаете это в RDB, в какой-то момент времени (когда вы должны начать масштабирование по горизонтали), вам также необходимо будет начать удаление SQL-соединений и объединить данные на уровне приложений.
Даже 10gen рекомендует использовать «ручные» ссылочные идентификаторы: http://www.mongodb.org/display/DOCS/Database+References