многие ко многим отношения с 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
на массиве, хранящем _id
s (проектов или пользователей).
для 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()
будет делать все, что вам хотеть. Я думаю, что неплохо сохранить схему пользователя с минимальной информацией, они выглядят как изолированные объекты, и они могут понадобиться вам для других целей.