2016-05-31 2 views
0

Я читал много документации и примеров здесь, в Stackoverflow, но я не совсем уверен в своих выводах, поэтому поэтому я прошу помочь.MongoDb много для многих с большими отношениями

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

Один из способов создать устройство в MongoDb является:

Пользователь:

{ 
"name":"User1", 
"films":[filmId1, filmId2, filmId3, filmId4] //ObjectIds from Films 
} 

Фильм:

{ 
"name": "The incredible MongoDb Developer", 
"watched_by": [userId1, userId2, userId3] //ObjectsIds from User 
} 

Хорошо, это может работать, если количество пользователей/фильмов является низким, но, например, если мы ожидаем, что в одном фильме будут пользователи в 800 тыс., размер массива будет близок к: 800k * 12 байт ~ 9,5 МБ, что почти соответствует максимальному размеру 16 МБ для файла BSON.

В этом случае существует другой подход, чем типичный реляционный мир, который создает промежуточную коллекцию для отношений?

Кроме того, я не знаю, будет ли читать и анализировать JSON около 10 МБ, будет иметь лучшую производительность по сравнению с классическим реляционным способом.

Спасибо

+0

Не могли бы вы объяснить, почему вы хотите сохранить ссылки на пользователя в документах для фильма? То, что я хотел написать, становится небольшим эссе по 4 возможностям, которые могут быть для меня или нет. – malarzm

ответ

2

Для пленок, если включить зрителей, вы могли бы в конечном итоге ударил 16MB size limit of BSON documents, как ты правильно сказал.

Включение фильмов, которые пользователь видел в массиве, является жизнеспособным способом, в зависимости от ваших вариантов использования. Особенно, если вы хотите иметь отношения с атрибутами (например, дату и место просмотра), делать обновления и статистический анализ становится менее результативным (вам нужно будет $unwind ваши документы сначала, последующие $matches становятся более дорогостоящими и еще много чего).

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

Учитывая коллекцию со структурой как

{ 
    _id: someObjectId, 
    date: ISODate("2016-05-05T03:42:00Z"), 
    movie: "nameOfMovie", 
    user: "username" 
} 

у вас есть все под рукой, чтобы легко ответить на следующие типовые вопросы:

  1. Для данного пользователя, какие фильмы он видел за последние 3 месяца, в порядке убывания даты?

    db.views.aggregate([ 
        {$match:{user:userName, date:{$gte:threeMonthAgo}}}, 
        {$sort:{date:-1}}, 
        {$group:{_id:"$user",viewed:{$push:{movie:"$movie",date:"$date"}}}} 
    ]) 
    

    или, если вы нормально с итератора, даже проще с:

    db.views.find({user:username, date:{$get:threeMonthAgo}}).sort({date:-1}) 
    
  2. Для данного фильма, сколько пользователей видели его на 30 мая этого года?

    db.views.aggregate([ 
    {$match:{ 
        movie:movieName, 
        date{ 
        $gte:ISODate("2016-05-30T00:00:00"), 
        $lt:ISODate("2016-05-31T00:00:00")} 
    }}, 
    {$group:{ 
        _id: "$movie", 
        views: {$sum:1} 
    }} 
    ]) 
    

    Причина, почему я использую агрегацию здесь вместо .Count() на результат является SERVER-3645

  3. Для данного фильма, показать все пользователи, которые видели его.

    db.views.find({movie:movieName},{_id:0,user:1}) 
    

Существует вещь, чтобы отметить: Так как мы использовали имена и названия фильмов, соответственно, мы не нужен JOIN (или нечто подобное), которые должны дать нам хорошую производительность. Кроме того, при добавлении записей нам не нужно выполнять довольно дорогостоящие операции обновления. Вместо обновления мы просто вставляем данные.

+0

Большое спасибо за ваш ответ :) – pianista

Смежные вопросы