Относится к базе данных NoSQL - PullRequest
5 голосов
/ 13 января 2012

Этот вопрос предназначен для всех экспертов по NoSQL и особенно для специалистов по mongoDB.Я начал с разработки реляционной БД для проекта, но клиент хочет, чтобы мы использовали БД, которая может легко масштабироваться.Для достижения этой цели мы решили использовать mongoDB.В эти дни у меня возникают проблемы с отображением моей реляционной модели для NoSQL.У меня есть таблица пользователей, которая имеет отношение "многие ко многим" со многими другими таблицами, как показано ниже:

relational DB

У меня есть несколько вариантов при преобразовании ее в 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>
}

Вариант 2 (только с внешними ключами в пользователях):

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 более реляционен, когда в таблице пользователей есть только монеты других таблиц.Преимущество этой опции заключается в том, что обновление битвы или предмета не требует больших затрат, так как ссылки на строки не копируются.С другой стороны, когда пользователь входит в систему, нам нужно будет найти все ссылочные юниты, битвы, предметы и локации, чтобы ответить полным объектом пользователя.

Вариант 3 противоположен варианту 2, где mongoIds таблицы пользователейхранятся в других таблицах.Этот вариант мне не очень нравится.

Я был бы очень признателен, если бы кто-то смог мне помочь или придумал лучшую модель.

Редактировать:

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

Ответы [ 2 ]

5 голосов
/ 13 января 2012

Во-первых, 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 будет предпочтительнее.Имейте в виду проблему с несколькими авторами.

1 голос
/ 13 января 2012

Вариант 2 - это путь.

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

Даже 10gen рекомендует использовать «ручные» ссылочные идентификаторы: http://www.mongodb.org/display/DOCS/Database+References

...