Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing one-one and one-many references - Mongoose

I have an Assignment schema which has references to Groups and Projects.

Assignment == Group [One-One Relationship]
Assignment == Projects [One-Many Relationship]

Below is my Asssignment Schema

var AssignmentSchema = new Schema({
    name: String,
    group: {
        type: Schema.Types.ObjectId,
        ref: 'Group'
    },
    projects: [{type: mongoose.Schema.Types.ObjectId, ref: 'Project'}],
});

If a Group/Project is removed, how can i update my Assignment Schema.

var ProjectSchema = new Schema({
    name: String
});

var GroupSchema = new Schema({
    name: String
});

From couple of answers in stackoverflow, i came to know about the remove middleware, but i am not sure how to implement it for one-one and one-many relationship. Can anyone show me an example of doing it.

ProjectSchema.pre('remove', function(next){
    this.model('Assignment').update(

    );
});
like image 622
Shane Avatar asked Sep 19 '15 23:09

Shane


2 Answers

Relationships:

  1. A one-to-one is a relationship such that a state has only one capital city and a capital city is the capital of only one state
  2. A one-to-many is a relationship such that a mother has many children, and the children have only one mother
  3. A many-to-many is a relationship such that a book can be written by several authors or co-authors, while an author can write several books.

one-one relationship - If a Project/Group is removed, how can i update my Assignment Schema.

Typically you will have one project mapped to one assignment and similarly one assignment mapped to one project. what you can do here is removing a project and then find the associated project in assignment model and remove their references.

delete: function(req, res) {
   return Project.findById(req.params.id, function(err, project){
         return project.remove(function(err){
             if(!err) {
                 Assignment.update({_id: project.assignment}}, 
                      {$pull: {projects: project._id}}, 
                          function (err, numberAffected) {
                            console.log(numberAffected);
                      } else {
                        console.log(err);                                      
                    }
                  });
            });
        });
}

one-many relationship - If a Project/Group is removed, how can i update my Assignment Schema.

In this scenario we are removing a project and then finding all the assignments which belongs to this project and removing its reference from them. Here the situation is, there can be many assignments for a single project.

delete: function(req, res) {
   return Project.findById(req.params.id, function(err, project){
         return project.remove(function(err){
             if(!err) {
                 Assignment.update({_id: {$in: project.assingments}}, 
                      {$pull: {project: project._id}}, 
                           function (err, numberAffected) {
                            console.log(numberAffected);
                      } else {
                        console.log(err);                                      
                    }
                  });
            });
        });
}

Remove middleware

You could achieve the same thing via middleware as pointed out by Johnny, just a correction on that..

ProjectSchema.pre('remove', function (next) {
    var project = this;
    project.model('Assignment').update(
        { projects: {$in: project.assignments}}, 
        { $pull: { project: project._id } }, 
        { multi: true }, 
        next
     );
});

Typically there can be many projects belonging to an assignment and many assignments belonging to the same project. You will have an assignment column in your Project Schema where one project will relate to multiple assignments.

Note: remove middleware won't work on models and it would only work on your documents. If you are going with remove middleware ensure in your delete function, you find project by id first and then on the returned document apply the remove method, so for the above to work... your delete function would look like this.

delete: function(req, res) {
   return Project.findById(req.params.id, function(err, project){
         return project.remove(function(err){
             if(!err) {
                  console.log(numberAffected);
             } 
           });                
    });
 }
like image 55
Thalaivar Avatar answered Sep 19 '22 15:09

Thalaivar


In the remove middleware, you're defining the actions to take when a document of the model for that schema is removed via Model#remove. So:

  • When a group is removed, you want to remove the group reference to that group's _id from all assignment docs.
  • When a project is removed, you want to remove the projects array element references to that project's _id from all assignment docs.

Which you can implement as:

GroupSchema.pre('remove', function(next) {
    var group = this;
    group.model('Assignment').update(
        { group: group._id }, 
        { $unset: { group: 1 } }, 
        { multi: true },
        next);
});

ProjectSchema.pre('remove', function (next) {
    var project = this;
    project.model('Assignment').update(
        { projects: project._id }, 
        { $pull: { projects: project._id } }, 
        { multi: true }, 
        next);
});
like image 32
JohnnyHK Avatar answered Sep 19 '22 15:09

JohnnyHK