Zernst
Zernst

Reputation: 325

Mongoose find by parameters including sub-array

I am creating an app where a job is created and that job's id is added to another collection (client) so the job can be referenced from the client itself. I have been able to add the job's id to the client's collection so far, but I am having trouble figuring out how to remove the job's id from the client's collection if the job is deleted. This is because the id is stored as a sub-collection within the client. The code I am trying to get to work is below:

// delete
app.delete("/jobs/:id", function(req, res){ 

            Client.find({jobs._id: req.params.id}, function (err, foundClient){  //This part doesn't work
                if (err) {
                    console.log(err);
                } else {
                    // Add id identifier to Client
                    foundClient.jobs.pull(req.params.id);
                    foundClient.save();
                }
            }); 
//  Delete Job
    Job.findByIdAndRemove(req.params.id, function(err, deletedJob){
        if (err){
            console.log(err)
        } else {            
            //  Redirect
            res.redirect("/jobs");
        }
    });
});

I am trying to get the logic of this part to work:

Client.find({jobs._id: req.params.id}, 

Here is the Client Schema

// =======================Client Schema

var clientSchema = new mongoose.Schema({
    organization_name: String,
    first_name: String,
    middle_name: String,
    last_name: String,
    email_address: String,
    phone_number: String,
    street: String,
    city: String,
    state: String,
    zip: String,
    description: String,
    active: {type: Boolean, deafult: true},
    date_added: {type: Date, default: Date.now},
    transactions: [{type: mongoose.Schema.Types.ObjectID, ref: "Transaction"}],
    jobs: [{type: mongoose.Schema.Types.ObjectID, ref: "Job"}]
});

module.exports = mongoose.model("Client", clientSchema);

Basically, what I am trying to tell it to do is find the Client where the client's jobs array contains an id equal to the id of the job being deleted. Of course, this syntax is incorrect, so it does not work. I have not been able to find documentation that explains how I would be able to do this. Is there a more straightforward way of doing this, the way I am writing it out here? I know that I can query the db this way if the job itself was not an array and only contained one singular variable. Is there a way to do this or do I need to write a completely separate looping function to get this to work? Thank you.

Upvotes: 0

Views: 926

Answers (1)

Mohammed Yousry
Mohammed Yousry

Reputation: 2184

jobs is an array of ids, so to find some documents in Client collection that have req.params.id in the jobs array, the query should be something like this

Client.find({jobs: req.params.id})

this will return an array of documents, each document has an array of jobs Ids

If you are sure that the req.params.id exists only in one document, you can use findOne instead of find, and this will return only one document with an array of jobs Ids

this is regarding the find part

regarding the remove job Id from jobs array, we can use one of the following methods

1- as you suggested, we can find the clients documents that have this job Id first, then remove this id from all the jobs arrays in all matching documents

like this

Client.find({ jobs: req.params.id }, async function (err, foundClients) {
    if (err) {
        console.log(err);
    } else {
        // loop over the foundClients array then update the jobs array

        for (let i = 0; i < foundClients.length; i++) {
            // filter the jobs array in each client 

            foundClients[i].jobs = foundClients[i].jobs || []; // double check the jobs array

            foundClients[i].jobs = foundClients[i].jobs.filter(jobId => jobId.toString() !== req.params.id.toString());
            // return all the jobs Ids that not equal to req.params.id
            // convert both jobId and req.params.id to string for full matching (type and value)

            await foundClients[i].save(); // save the document
        }

    }
});

2- we can use $pull array update operator to update the jobs array directly

something like this

Client.updateMany(
    { jobs: req.params.id }, // filter part
    {
        $pull: { jobs: { $in: [req.params.id] } } // update part
    },
    function (err) {
        if (err) {
            console.log(err);
        } else {
            console.log('job id removed from client documents successfully');
        }
    }
);

hope it helps

Upvotes: 1

Related Questions