Pelo contrário, as soluções 1 e 2 são sua melhor aposta. A solução 3 pode ser considerada quando a frequência de atualização/criação é muito menor em comparação com a frequência de leitura de projetos e usuários, pois mesmo que para atualizar/criar sejam necessárias duas consultas, a facilidade de leitura será compensada.
Para escolher entre as soluções 1 e 2, você precisa considerar as frequências de leitura. Você vai precisar de projetos de um usuário ou usos de um projeto com mais frequência e escolher de acordo com isso. Se você sentir que ambos têm relativamente a mesma frequência, é melhor manter o objeto de usuário o menos agrupado possível. Qualquer que seja a opção escolhida, considere manter um
index
na matriz que armazena o _id
s (de projetos ou usuários). Por ex.
userSchema = new Schema(
{//otherstuff
project_ids: [{type: Schema.Types.ObjectId, ref: 'Project'}})
...
})
userSchema.index({'project_ids':1})
ou
projectSchema = new Schema(
{//otherstuff
user_ids: [{type: Schema.Types.ObjectId, ref: 'User'}})
...
})
projectSchema.index({'user_ids':1})
Mantendo um índice no array de
_id
melhorará muito a velocidade de suas consultas no lado em que você teme que haja uma sobrecarga significativa. Mas mantenha o
index
somente se essa relação for uma relação importante com muitas consultas em andamento. Se este é apenas um recurso secundário do seu projeto, você pode fazer without
um índice também. Se o usuário puder fazer muitas coisas e tiver muitas relações, você precisará desse objeto de usuário constantemente em todo o aplicativo, portanto, se seu aplicativo não for específico do projeto, seria melhor não colocar os IDs do projeto no esquema do usuário . Mas como estamos apenas colocando os ids, não é uma sobrecarga de qualquer maneira. Não precisa se preocupar com isso.
Índice Reg em ambas as matrizes:Sim, você pode, claro. Mas quando você for para a solução 3, não precisará de um índice, pois não fará uma consulta para obter a lista de projetos de um usuário ou a lista de usuários em um projeto. A solução 3 torna a leitura muito fácil, mas a escrita um pouco complicada. Mas como você mencionou que seu caso de uso envolve
reading>>writing
, vá com a solução 3, mas sempre há o perigo de inconsistência de dados que você precisa cuidar. A indexação apenas torna as coisas mais rápidas. Vá até os documentos e faça um pouco de googling. Nada chique. Consultar arrays indexados é mais eficiente do que arrays normais. Por ex. Vamos supor que você use a solução 2. Armazene os IDs do projeto no campo project_ids.
Você pode obter os projetos de um usuário facilmente. Isso é direto.
Mas para obter usuários de project1. Você precisa de uma consulta como esta.
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.
Similarmente para a solução 1. Cada projeto possui o campo user_ids. Vamos supor que temos um user1. Para obter os projetos do usuário fazemos a seguinte consulta
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.
Se você está ponderando sobre a solução 1 versus a solução 2, a solução 1 é melhor, eu acho. Pode haver casos em que você precise do usuário sem seus projetos, mas as chances de exigir o projeto sem os usuários são muito baixas. Mas isso depende do seu caso de uso exato.