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

От многих до многих отношений с nosql (mongodb и mongoose)

Я делаю отношения со многими для многих с mongoDb и mongoose.js, я знаю, что есть много вариантов, моя ситуация такова:

У меня есть два документа, пользователь и проекты, у одного пользователя может быть много проектов, и у одного проекта может быть много пользователей, поэтому в моем случае у меня есть 4 варианта:

1 - массив id_user внутри документа проекта.

2 - массив id_project внутри пользовательского документа.

3 - массив id_user внутри документа проекта && & & Массив id_project внутри пользовательского документа.

4 - Третья таблица, отображающая отношения пользователя и проекта (например, реляционная база данных).

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

Вариант 3 хорош, но мне нужно будет сделать какую-то транзакцию, чтобы гарантировать, что оба документа будут записаны, это не так уж плохо, потому что оба документа будут гораздо более читаемыми, чем написанными

Опция 4 проще, потому что когда я добавляю одного пользователя в проект, просто добавляю новый документ с обоими идентификаторами (это хорошее решение, я думаю, потому что мне не нужно заботиться о транзакции, это хорошо решение?)

Итак, какое лучшее решение?

4b9b3361

Ответ 1

Наоборот, решение 1 и 2 - ваш лучший выбор. Решение 3 можно учитывать, когда частота обновления/создания очень меньше по сравнению с частотой чтения проектов и пользователей, так как даже при обновлении/создании требуется два запроса, легкость чтения будет компенсировать это.

Чтобы выбрать среди решений 1 и 2, вам необходимо учитывать частоты чтения. Будете ли вы нуждаться в проектах пользователя или использовать проект более часто и выбирать в соответствии с этим. Если вы считаете, что они имеют одинаковую частоту, лучше сохранить объект пользователя как можно менее сгруппированным. Какой бы вариант вы ни выбрали, подумайте о сохранении index в массиве, хранящем _id (проектов или пользователей).

Например,

userSchema = new Schema(
            {//otherstuff
               project_ids: [{type: Schema.Types.ObjectId, ref: 'Project'}})
              ...
            }) 
userSchema.index({'project_ids':1})

или

projectSchema = new Schema(
            {//otherstuff
               user_ids: [{type: Schema.Types.ObjectId, ref: 'User'}})
              ...
            }) 
projectSchema.index({'user_ids':1})

Сохранение индекса в массиве _id значительно улучшит скорость ваших запросов на стороне, где вы боитесь, что будут значительные накладные расходы.

Но сохраняйте index только в том случае, если это отношение является важным отношением к большому количеству запросов. Если это только побочная функция вашего проекта, вы можете сделать without и индекс.

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

Регистр Reg на обоих массивах: Да, вы можете сказать. Но когда вы идете на решение 3, вам вообще не нужен индекс, поскольку вы не будете делать запрос, чтобы получить список проектов пользователя или список пользователей в проекте. Решение 3 делает чтение очень простым, но написание немного громоздким. Но поскольку вы упомянули, что ваш вариант использования включает reading>>writing, идите с решением 3, но всегда существует опасность несогласованности данных, о которой вам нужно позаботиться.

Индексирование только ускоряет работу. Пройдите документы и сделайте немного поиска в Google. Ничего особенного. Запрос по индексированным массивам эффективен, чем обычные массивы. Напр. Предположим, вы используете решение 2. Сохраните идентификаторы проекта в поле project_ids.

Вы можете легко получить проекты пользователя. Это прямо.

Но получить пользователей проекта1. Вам нужен такой запрос.

User.find({project_ids:project._id},function(err,docs){
     //here docs will be the list of the users of project1
})
//The above query might be slow if the user base is large. 
//But it can be improved vastly by indexing the project_ids field in the User schema.

Similary для решения 1. Каждый проект имеет поле user_ids. Предположим, у нас есть user1. Чтобы получить проекты пользователей, мы делаем следующий запрос

Project.find({user_ids:user1._id},function(err,docs){
      //here docs will be the projects of user1
      //But it can be improved vastly by indexing the user_ids field in the Project schema.

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

Ответ 2

Хорошо решение 1 и 2 не выглядит так плохо! Если вы индексируете массив ObjectIds, вы можете напрямую получить доступ к тому, что хотите.

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

Я предпочитаю решение 1 с индексом по массиву. Я думаю, много раз вам нужно, чтобы объект проекта зависел от пользователя или напрямую от id, поэтому .find() сделает все, что вам нужно. Я думаю, что неплохо сохранить пользовательскую схему с минимальной информацией, они выглядят как изолировать объекты, и вам могут понадобиться их для других целей.