Как бы вы установили связь "многие ко многим" с MongoDB?
Например; скажем, у вас есть таблица пользователей и таблица ролей. У пользователей много ролей, а у ролей много пользователей. В мире SQL вы должны создать таблицу UserRoles.
Users:
Id
Name
Roles:
Id
Name
UserRoles:
UserId
RoleId
Как такие же отношения обрабатываются в MongoDB?
many-to-many
associations
mongodb
Джош Клоуз
источник
источник
Ответы:
В зависимости от потребностей вашего запроса вы можете поместить все в пользовательский документ:
{name:"Joe" ,roles:["Admin","User","Engineer"] }
Чтобы получить всех инженеров, используйте:
db.things.find( { roles : "Engineer" } );
Если вы хотите сохранить роли в отдельных документах, вы можете включить _id документа в массив ролей вместо имени:
{name:"Joe" ,roles:["4b5783300334000000000aa9","5783300334000000000aa943","6c6793300334001000000006"] }
и настройте такие роли, как:
{_id:"6c6793300334001000000006" ,rolename:"Engineer" }
источник
Вместо того, чтобы пытаться моделировать в соответствии с нашим многолетним опытом работы с СУБД, я обнаружил, что намного проще моделировать решения для репозитория документов с использованием MongoDB, Redis и других хранилищ данных NoSQL, оптимизируя варианты использования для чтения, учитывая при этом атомарность операции записи, которые должны поддерживаться сценариями использования записи.
Например, использование домена «Пользователи в ролях» следующее:
Это можно смоделировать в виде следующих шаблонов документов:
User: { _id: UniqueId, name: string, roles: string[] } Indexes: unique: [ name ] Role: { _id: UniqueId, name: string, users: string[] } Indexes: unique: [ name ]
Для поддержки частого использования, такого как функции, связанные с ролями, из объекта User, User.Roles намеренно денормализованы, хранятся как у пользователя, так и у Role.Users, имеющих дублированное хранилище.
Если это не совсем очевидно в тексте, но это тот тип мышления, который поощряется при использовании репозиториев документов.
Я надеюсь, что это поможет восполнить пробел в отношении считываемой стороны операций.
Со стороны записи рекомендуется моделировать в соответствии с атомарной записью. Например, если структуры документа требуют получения блокировки, обновления одного документа, затем другого и, возможно, большего количества документов, а затем снятия блокировки, вероятно, модель не работает. То, что мы можем создавать распределенные блокировки, не означает, что мы должны их использовать.
В случае модели «Пользователь в ролях» операциями, которые расширяют нашу атомарную защиту от записи, являются добавление или удаление пользователя из роли. В любом случае успешная операция приводит к обновлению как одного документа пользователя, так и одного документа роли. Если что-то не получается, очистку легко выполнить. Это одна из причин, по которой шаблон «Единица работы» довольно часто встречается там, где используются репозитории документов.
Операция, которая действительно расширяет нашу атомарную запись, предотвращающую блокировку, - это очистка роли, в результате чего многие обновления пользователя удаляют Role.name из массива User.roles. Эта операция очистки обычно не рекомендуется, но при необходимости может быть реализована путем упорядочивания операций:
В случае проблемы, которая, скорее всего, возникнет на шаге 2, откат выполняется просто, поскольку тот же набор имен пользователей из шага 1 может использоваться для восстановления или продолжения.
источник
Я только что наткнулся на этот вопрос и, хотя он старый, я подумал, что было бы полезно добавить пару возможностей, не упомянутых в приведенных ответах. Кроме того, за последние несколько лет ситуация немного изменилась, поэтому стоит подчеркнуть, что SQL и NoSQL становятся все ближе друг к другу.
Один из комментаторов высказал мудрое предостерегающее отношение: «если данные реляционные, используйте реляционные». Однако этот комментарий имеет смысл только в реляционном мире, где схемы всегда предшествуют приложению.
ОТНОСИТЕЛЬНЫЙ МИР: Структурируйте данные> Напишите приложение, чтобы получить его
NOSQL WORLD: Разработайте приложение> Соответственно структурируйте данные
Даже если данные являются реляционными, вариант NoSQL все же возможен. Например, отношения "один ко многим" вообще не проблема и широко освещаются в документации MongoDB.
РЕШЕНИЕ В 2015 ГОДУ ПРОБЛЕМЫ 2010 ГОДА
После публикации этого вопроса были предприняты серьезные попытки приблизить noSQL к SQL. Команда под руководством Янниса Папаконстантину из Калифорнийского университета (Сан-Диего) работает над FORWARD , реализацией SQL ++, которая вскоре может стать решением постоянных проблем, подобных той, что опубликована здесь.
На более практическом уровне выпуск Couchbase 4.0 означал, что впервые вы можете выполнять собственные JOIN в NoSQL. Они используют свой собственный N1QL. Это пример
JOIN
из их руководств :SELECT usr.personal_details, orders FROM users_with_orders usr USE KEYS "Elinor_33313792" JOIN orders_with_users orders ON KEYS ARRAY s.order_id FOR s IN usr.shipped_order_history END
N1QL позволяет выполнять большинство, если не все операции SQL, включая агрегирование, фильтрацию и т. Д.
НЕ ТАК НОВОЕ ГИБРИДНОЕ РЕШЕНИЕ
Если MongoDB по-прежнему является единственным вариантом, я хотел бы вернуться к своей точке зрения, что приложение должно иметь приоритет над структурой данных. Ни в одном из ответов не упоминается гибридное встраивание, при котором большинство запрашиваемых данных внедряются в документ / объект, а ссылки сохраняются в меньшинстве случаев.
Пример: может ли ждать информация (кроме имени роли)? может ли загрузка приложения быть быстрее, если не запрашивать ничего, что пользователю еще не нужно?
Это может произойти, если пользователь входит в систему и ему / ей нужно увидеть все параметры для всех ролей, к которым он / она принадлежит. Однако пользователь является «инженером», и варианты для этой роли используются редко. Это означает, что приложение должно отображать параметры только для инженера, если он / она захочет по ним щелкнуть.
Это может быть достигнуто с помощью документа, который сообщает приложению в начале (1), к каким ролям принадлежит пользователь и (2) где получить информацию о событии, связанном с конкретной ролью.
{_id: ObjectID(), roles: [[“Engineer”, “ObjectId()”], [“Administrator”, “ObjectId()”]] }
Или, что еще лучше, проиндексируйте поле role.name в коллекции ролей, и вам, возможно, также не потребуется встраивать ObjectID ().
Другой пример: информация обо всех запрошенных ролях ВСЕГДА?
Также может быть случай, когда пользователь входит в панель управления и 90% времени выполняет задачи, связанные с ролью «Инженер». Гибридное встраивание может быть выполнено для этой конкретной роли полностью, а ссылки сохранены только для остальных.
{_id: ObjectID(), roles: [{name: “Engineer”, property1: value1, property2: value2 }, [“Administrator”, “ObjectId()”] ] }
Отсутствие схемы - это не просто характеристика NoSQL, в этом случае это может быть преимуществом. Совершенно верно вкладывать различные типы объектов в свойство «Roles» пользовательского объекта.
источник
в случае, когда сотрудник и компания являются сущностью-объектом, попробуйте использовать следующую схему:
employee{ //put your contract to employee contracts:{ item1, item2, item3,...} } company{ //and duplicate it in company contracts:{ item1, item2, item3,...} }
источник