Подтвердить что ты не робот

Лучшая модель для представления от многих до многих отношений с атрибутами в MongoDB

Какой самый способ "mongo" для представления отношений "многие ко многим", которые имеют атрибуты?

Итак, например:

Введение


Таблицы MYSQL

people = > firstName, lastName, ...

Movies = > name, length ..

peopleMovies = > movieId, personId, language, role

Решение 1


Вставить людей в фильмы...?

В MongoDB я понимаю, что это хорошо для denormalize and embed, но я не хочу, чтобы embed люди в фильмы, это просто логически не имеет смысла. Потому что люди не обязательно должны принадлежать только к фильмам.

Решение 2


people и Movies будут две отдельные коллекции. people = > embed [{movieId: 12, personId: 1, language: "English", role: "Main"} ...]

Movies = > embed [{movieId: 12, personId: 1, language: "English", role: "Main"} ...]

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

Решение 3


Мы также можем сделать что-то гораздо более реляционное, и в итоге получим три коллекции

people = > firstName, lastName, ... Movies = > name, length .. Castings = > movieId, personId, language, role

Проблема заключается в том, что из-за отсутствия утверждения объединения в MongoDB требуется 3 queries перейти от людей → к фильмам и наоборот.

Вот мой вопрос, какие еще есть способы моделирования чего-то подобного в MongoDB и более NoSQL. С точки зрения предоставленных решений, какой из них будет лучшим с точки зрения производительности и согласия в манго.

4b9b3361

Ответ 1

Во многих отношениях meteor API поощряет плоские реляционные документы, однако MongoDB является нереляционным хранилищем данных. Этот конфликт, к сожалению, оставлен в качестве упражнения для разработчика, чтобы решить.

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

Причины, по которым вам следует выбрать реляционную модель

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

  • DDP работает с документами. Все комментарии будут отправляться каждый раз, когда будет добавлен новый комментарий в том же сообщении.

  • allow и deny действуют правила. Может быть необоснованно ожидать, что одни и те же правила применяются одновременно к обоим сообщениям и комментариям.

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

  • Реляционные базы данных существуют по уважительным причинам. Один из них - избежать проблемы с множественным изменением, присущей вашему второму решению.

Причины, по которым вы должны выбрать встроенную модель

  • Соединения не поддерживаются MongoDB самостоятельно, и нет основного пакета для создания реактивного соединения.

Рекомендации

Используйте свое третье решение. По моему опыту, причины выбора реляционной модели намного перевешивают ограничения, налагаемые хранилищем данных. Конечно, преодоление отсутствия объединений непросто, но боль, скорее всего, будет изолирована только от нескольких функций публикации. Вот некоторые ресурсы, которые я очень рекомендую:

Если вам нужна дополнительная информация, пожалуйста, прокомментируйте ниже, и я обновлю свой ответ.

Ответ 2

Я думаю, вы должны денормализовать свои коллекции. Важным моментом при разработке коллекций и документов MongoDB является представление о ваших взглядах. Какие данные необходимы для отображения вашего представления? Идея состоит в том, что вы должны попытаться, чтобы эти данные были частью вашего документа.

Например, в вашем случае у вас, вероятно, есть представление для Movies, где вы хотите отображать информацию о фильме. Но эта страница о фильме, возможно, нуждается только в базовой информации о каждом человеке (имя, фамилия, URL-адрес фотографии). Не все. И наоборот, страница о человеке, вероятно, перечислит все фильмы, но также снова нужно только подмножество информации о каждом фильме, например, название, год и URL-адрес плаката.

Таким образом, один вариант состоит в том, чтобы иметь две коллекции, но затем вставлять (денормализовать) только те несколько полей, которые вам нужны между коллекциями. Так, например, в коллекции Movies будет поле people, которое будет представлять собой массив поддокументов. И в коллекции people было бы поле Movies, которое было бы массивом поддокументов, с теми дополнительными полями, которые вы хотите указать роль и т.д.

Таким образом, документы могут быть примерно такими. Для фильмов:

{
  _id: "AAA",
  title: "...",
  year: 2015,
  length: 120,
  posterURL: "...",
  people: [
    {
      person: {
        _id: "BBB",
        firstName: "...",
        lastName: "...",
        photoURL: "..."
      },
      role: "..."
    }
  ]
}

Для людей:

{
  _id: "BBB",
  firstName: "...",
  lastName: "...",
  photoURL: "...",
  movies: [
    {
      _id: "AAA",
      title: "...",
      year: 2015,
      posterURL: "..."
    }
  ]
}

Конечно, вопрос заключается в том, как синхронизировать эти поля. Что делать, если вы обновляете URL-адрес фоторепортажа для фильма, вы хотите, чтобы он обновлялся и во всех документах Person. Чтобы решить эту проблему, мы разработали PeerDB, пакет для определения отношений между коллекциями, который затем гарантирует их синхронизацию.

Итак, в вашем случае у меня были бы такие коллекции, определенные в PeerDB, в CoffeeScript:

class People extends Document
  @Meta
    name: 'People'

class Movies extends Document
  @Meta
    name: 'Movies'
    fields: =>
      people: [
        person: @ReferenceField People, ['firstName', 'lastName', 'photoURL'], true, 'movies', ['title', 'year', 'posterURL']
      ]

Вкратце, это определение говорит о том, что поле people.person должно быть ссылкой на коллекцию people и храниться в синхронизации для firstName, lastName, photoURL. Кроме того, обратная ссылка на поле должно быть сделано в people документы под полем Movies с title, year, posterURL.

Довольно просто. Но есть некоторые недостатки. Массивы могут быть очень большими (может быть, не для фильмов и людей, но для некоторых других данных), что может сделать документы слишком большими для границ MongoDB на одном документе (на данный момент 16 МБ). Кроме того, если вы заметили, вы увидите, что для документов people нет информации о роли в списке фильмов. Это связано с тем, что роль не является частью ссылочного документа, но это то, что находится рядом с ссылкой. Что делать, если вы хотите отобразить роль фильма, на котором находился человек на странице пользователя/просмотре?

Итак, может быть, было бы лучше иметь три коллекции, одну для базовой информации о фильмах, другую для людей, а затем сборник для связи между людьми и фильмами. Таким образом, данные могут быть, возможно, что-то вроде, для фильмов:

{
  _id: "AAA",
  title: "...",
  year: 2015,
  length: 120,
  posterURL: "..."
}

Для людей:

{
  _id: "BBB",
  firstName: "...",
  lastName: "...",
  photoURL: "..."
}

Для кастинга:

{
  _id: "...",
  movie: {
    _id: "AAA",
    title: "...",
    year: 2015,
    posterURL: "..."
  },
  person: {
    _id: "BBB",
    firstName: "...",
    lastName: "...",
    photoURL: "..."
  },
  role: "..."
}

И определения PeerDB:

class People extends Document
  @Meta
    name: 'People'

class Movies extends Document
  @Meta
    name: 'Movies'

class Casting extends Document
  @Meta
    name: 'Casting'
    fields: =>
      person: @ReferenceField People, ['firstName', 'lastName', 'photoURL']
      movie: @ReferenceField Movies, ['title', 'year', 'posterURL']

PeerDB будет следить за тем, чтобы все было синхронизировано. Он также удалит листинг документа, если фильм или человек будут удалены из базы данных.

Это позволяет вам сделать публикацию Meteor, которая является эффективной и не требует динамического построения связанных запросов. Вы просто публикуете коллекцию Casting, и это она. Вы можете даже запросить какое-то условие. Например, вы хотите отобразить всех режиссеров, отсортированных по firstName и lastName и их фильмам? Возможно только с одним запросом.