многие ко многим отношения с nosql (mongodb и Мангуст)

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

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

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

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

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

4-третья таблица сопоставления пользователя и проекта отношения(как реляционная база данных.)

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

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

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

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

2 ответов


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

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

для ex.

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

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

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

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

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

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 Лучше, я думаю. Могут быть случаи, когда вам нужен пользователь без его проектов, но шансы потребовать проект без пользователей довольно низки. Но это зависит от вашего точного варианта использования.


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

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

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