MongoDB нормализация, внешний ключ и присоединение
Перед тем, как я действительно глубоко погрузился в MongoDB в течение нескольких дней, я подумал, что задам довольно простой вопрос о том, должен ли я погрузиться в него вообще или нет. У меня практически нет опыта работы с nosql.
Я немного прочитал о некоторых преимуществах баз данных документов, и я думаю, что для этого нового приложения они будут действительно хороши. Делать избранные, комментарии и т. Д. Всегда сложно для многих типов объектов (множество связей m-to-m) и подклассов - с этим трудно справиться.
У меня также есть структура, которую будет трудно определить в SQL, потому что она чрезвычайно вложенная и переводит в документ намного лучше, чем 15 различных таблиц.
Но я запутался в нескольких вещах.
Желательно ли по-прежнему нормализовать вашу базу данных? Я действительно не хочу обновлять несколько записей. Это все еще как люди подходят к дизайну базы данных в MongoDB?
Что происходит, когда пользователь добавляет книгу в избранное, и этот выбор все еще сохраняется в пользовательском документе, но затем книга удаляется? Как отношения обособляются без внешних ключей? Я сам несу ответственность за удаление всех ссылок?
Что произойдет, если пользователь выбрал книгу, которой больше не существует, и я запросил ее (какое-то соединение)? Должен ли я сделать здесь отказоустойчивость?
2 ответа
MongoDB не поддерживает отношения внешних ключей на стороне сервера, нормализация также не рекомендуется. Если возможно, вы должны встроить свой дочерний объект в родительские объекты, это повысит производительность и сделает ненужными внешние ключи. Тем не менее, это не всегда возможно, поэтому существует специальная конструкция DBRef, которая позволяет ссылаться на объекты в другой коллекции. Тогда это может быть не так быстро, потому что БД должна делать дополнительные запросы для чтения объектов, но допускает вид ссылки на внешний ключ.
Тем не менее, вам придется обрабатывать ваши ссылки вручную. Только при поиске вашего DBRef вы увидите, существует ли он, БД не будет просматривать все документы, чтобы искать ссылки и удалять их, если цель ссылки больше не существует. Но я думаю, что удаление всех ссылок после удаления книги потребует одного запроса на коллекцию, не более, так что на самом деле это не так сложно.
Если ваша схема более сложная, то, вероятно, вам следует выбрать реляционную базу данных, а не nosql.
Также есть книга о проектировании баз данных MongoDB: Дизайн документов для MongoDB
ОБНОВЛЕНИЕ Книга выше недоступна, но из-за популярности MongoDB есть много других. Я не буду связывать их все, так как такие ссылки могут измениться, простой поиск на Amazon показывает несколько страниц, поэтому их не должно быть проблемой.
См. Страницу руководства MongoDB для "Ручных ссылок" и DBRef для получения дополнительной информации и примеров.
Выше @TomaaszStanczak заявляет
MongoDB не поддерживает отношения внешних ключей на стороне сервера, нормализация также не рекомендуется. Если возможно, вы должны встроить свой дочерний объект в родительские объекты, это повысит производительность и сделает ненужными внешние ключи. Тем не менее, это не всегда возможно...
Нормализм не одобряет Монго. Чтобы было ясно, мы говорим о двух принципиально разных типах отношений, которые могут иметь два объекта данных. В одном из них один дочерний объект принадлежит исключительно родительскому объекту. В этот тип отношений монго-способ заключается в том, чтобы встраивать.
В другом классе отношений две сущности существуют независимо - имеют независимые времена жизни и отношения. Монго желает, чтобы такого рода отношения не существовали, и разочарованно молчит, как именно с этим бороться. Встраивание это просто не решение. Нормализация не поощряется и не поощряется. Монго просто дает вам два механизма, чтобы справиться с этим; Ручные ссылки (аналогично ключу с ограничением внешнего ключа, связывающего две таблицы) и DBRef (другой, немного более структурированный способ сделать то же самое). В этом случае базы данных SQL выигрывают.
Ответы как Томаша, так и Фрэнсиса содержат хороший совет: что "нормализация" не препятствует Mongo, но вы должны сначала подумать об оптимизации дизайна документа базы данных, прежде чем создавать "ссылки на документы". DBRefs
были упомянуты Томашем, однако, как он упомянул, не являются "волшебной пулей" и требуют дополнительной обработки, чтобы быть полезными.
Что теперь возможно, начиная с версии 3.2 MongoDB, так это выдавать результаты, эквивалентные SQL JOIN, с помощью оператора этапа конвейера агрегирования $lookup. Таким образом, вы можете получить "нормализованную" структуру документа, но при этом получить консолидированные результаты. Чтобы это сработало, вам необходимо создать уникальный ключ в целевой коллекции, который, надеюсь, будет значимым и уникальным. Вы можете обеспечить уникальность, создав уникальный индекс для этого поля.
Использование $lookup довольно простое. Взгляните на документацию здесь: https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/. Запуститьaggregate()
в исходной коллекции (т.е. в "левой" таблице). Параметр from - это целевая коллекция (то есть "правая" таблица). Параметр localField будет полем в исходной коллекции (т. Е. " Внешним ключом"). Параметр foreignField будет совпадающим полем в целевой коллекции.
Что касается потерянных документов, исходя из вашего вопроса, я предполагаю, что вы думаете о традиционном наборе ограничений СУБД, каскадном удалении и т. Д. Опять же, начиная с версии 3.2 MongoDB, есть встроенная поддержка проверки документов. Взгляните на эту статью на StackOver: Как применять ограничения в MongoDB? Посмотрите на второй ответ от JohnnyHK
У издателей Packt есть куча хороших книг по MongoDB. (Полное раскрытие информации: я написал пару из них.)