MongoDB много-ко-многим Ассоциации


Как бы вы сделали много-ко-многим ассоциации с MongoDB?

например, допустим у вас есть таблица пользователей и таблица ролей. Пользователи имеют много ролей, а роли имеют много пользователей. В SQL land вы создадите таблицу UserRoles.

Users:
    Id
    Name

Roles:
    Id
    Name

UserRoles:
    UserId
    RoleId

Как же отношения обрабатываются в MongoDB?

4 119

4 ответа:

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

{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 путем оптимизации для случаев использования чтения, будучи внимательным к атомарным операциям записи, которые должны поддерживаться случаями использования записи.

например, использование домена "пользователи В ролях":

  1. Роль - Создание, Чтение, Обновление, Удаление, Список Пользователи, Добавить пользователя, удалить пользователя, очистить всех пользователей, индекс пользователя или аналогичный поддержке "is User In Role" (операции, такие как контейнер + собственные метаданные).
  2. User-Create, Read, Update, Delete (операции CRUD, такие как автономная сущность)

Это можно смоделировать как следующие шаблоны документов:

User: { _id: UniqueId, name: string, roles: string[] }
    Indexes: unique: [ name ]
Role: { _id: UniqueId, name: string, users: string[] }
    Indexes: unique: [ name ]

для поддержки высокочастотных применений, таких как связанные с ролями функции от объекта User, User.Роли намеренно денормализованы, хранятся на пользователь, а также роль.Пользователи, имеющие дубликат хранилища.

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

Я надеюсь, что это поможет преодолеть разрыв в отношении стороны чтения операций.

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

для случая пользователя в модели ролей операции, которые растягивают наше атомарное предотвращение записи блокировок, добавляют или удаляют пользователя из роли. В любом случае успешная операция приводит к обновлению как одного пользователя, так и одного документа роли. Если что-то не удается, это легко выполните очистку. Это одна из причин, по которой шаблон Unit of Work появляется довольно много, где используются хранилища документов.

операция, которая действительно растягивает наше атомарное предотвращение записи блокировок, очищает роль, что приведет к тому, что многие обновления пользователей удалят Role.name от пользователя.массив ролей. Эта операция clear тогда обычно не рекомендуется, но при необходимости может быть реализована путем упорядочения операций:

  1. список пользователей от роли.пользователи.
  2. повторите имена пользователей из Шага 1, Удалите имя роли из пользователя.роли.
  3. четкая роль.пользователи.

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

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

РЕЛЯЦИОННЫЙ МИР: данные структуры > написать приложение, чтобы получить его
NOSQL WORLD: применение конструкции > данные по структуры соответственно

даже если данные реляционные, NoSQL по-прежнему является опцией. Например, отношения "один ко многим" не являются проблемой вообще и широко освещаются в MongoDB docs

В 2015 ГОДУ РЕШЕНИЯ 2010 Проблема

С момента публикации этого вопроса были предприняты серьезные попытки приблизить noSQL к SQL. Команда под руководством Янниса Папаконстантину из Калифорнийского университета (Сан-Диего) работает над вперед, реализация SQL++, которая вскоре может стать решением постоянных проблем, подобных той, что размещена здесь.

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

в случае, когда работник и компания субъект-объект попробуйте использовать следующую схему:

employee{
   //put your contract to employee
   contracts:{ item1, item2, item3,...}
}

company{
   //and duplicate it in company
   contracts:{ item1, item2, item3,...}
}