简体   繁体   中英

How to setup n:m relations in feathersjs with mongoose?

I am developing the first project with feathersjs and wanted to use it with MongoDB (and mongoose as a supported driver). However, I came to a point, where some optimizations can happen (that's what I think...)

I have an n:m relation between a user-entity and a project-entity. So a user can have many projects, and a project can have many users.

I found out i can declare this relation with mongoose as follows:

user.model:

projects: [
  { type: mongooseClient.Schema.Types.ObjectId, ref: 'Projects' }
]

project.model

users: [
  { type: mongooseClient.Schema.Types.ObjectId, ref: 'Users' }
]

This works as I want it to. Now, there are some things I learned about MongoDB, so it doesn't care about any object-relations when eg removing a project. So when a project is deleted, the user-entity will keep the ID of the deleted project in its "projects-attribute".

I manually implemented a logic for this as follows:

async remove(id: string, params?: Params) {

const project = (await app.service("projects").get(id)) as ProjectData
const users = project.users;
// User-Table of projects must be set
for(let user of users!) {
  const newUserProjects = (await app.service("users").get(user)).projects!.filter(p => p.toString() !== id.toString());

  app.service("users").patch(user!, {
    projects: newUserProjects ? newUserProjects : []
  });
}
return super.remove(id, params);

}

As should be obvious now, I am pretty new to this stack - especially MongoDB. Is there any better way to handle this situation? Like so, I would have many database-accesses - which's not really a good thing. Of course, there are more of these situations (patching, creating, etc.).

Thanks in advance! Would be happy if someone can help me out with a good idea or some MongoDB / mongoose magic for this problem!

VForsmann

It's a common problem, I usually simply solve it with only keeping reference in one the models.

If I read OP correctly, then I assume

  • 1 Project can have X users
  • 1 User can have X projects
  • if 1 Project is deleted, all references to the project should be removed as well (from user).

Simple Solution

To reduce the number of databasse-accesses when it comes to removing all those unneeded reference, a simple solution would be just to keep the relation bound to one of the models, either User or Project. Since the Project would be the one thing, which gets probably deleted more often than User, I would suggest keeping the relation at the Project Model.

// Project Model
users: [
  { type: mongooseClient.Schema.Types.ObjectId, ref: 'Users' }
]

Now you might think, if you don't keep reference to Projects in the User Model, how do you get all projects of 1 specific user? Easy:

// just an example, using expressjs route
// but part of the mongoose query should be the same

app.get('/user/:id/projects', (req, res) => {

  const userid = req.params.id;
  const userprojects = await Project.find({ users: {$in: [userid]}}).exec();
  return res.status(200).json(userprojects);

});

What you see there ☝ is how you could use the Project Model to find all projects of a specific user. Now if the project is deleted, nobody ends up having a dead-end reference to it.

Cons

So we reduced the number of database-accesses, but still, if we delete a user, the projects on the other side might still have that reference in it - there is something else I want you to check out: Mongoose Middleware !

// you can add a pre hook to your User Schema, like this 
UserSchema.pre('deleteOne', { document: true }, function(next) {
  console.log(this); // this : User Document to be deleted
  // do stuff here
  next();
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM