Given this model, how to delete a nested array item with updateOne (mongoose)?

Viewed 606

I am trying to remove an array item with "updateOne" method but my query is not matching the right record in the model structure that I have. Given an email, I would like to find the array item with the provided email and pulls it out, remove it. (There is no array item with the same email)

My model is like so:

var mongoose = require('mongoose');

var teamMemberModelSchema = new mongoose.Schema({
     _id: false,
    "email": {
        "type": String,
        "required": true,
        "minlenght": 5,
        "maxheight": 50
    },
    "name": {
        "type": String,
        "required": true,
        "minlenght": 5,
        "maxheight": 256
    },
    "role": {
        "type": String,
        "required": true,
        "minlenght": 20,
        "maxheight": 256
    },
    "twitter": {
        "type": String,
        "required": true,
        "minlenght": 1,
        "maxheight": 100
    },
    "facebook": {
        "type": String,
        "required": true,
        "minlenght": 1,
        "maxheight": 100
    },
    "linkedin": {
        "type": String,
        "required": true,
        "minlenght": 1,
        "maxheight": 100
    },
});

var teamModelSchema = new mongoose.Schema({
    "title": {
        "type": String,
        "required": true,
        "minlenght": 5,
        "maxheight": 20
    },
    "headline": {
        "type": String,
        "required": true,
        "minlenght": 5,
        "maxheight": 30
    },
    "description": {
        "type": String,
        "required": true,
        "minlenght": 5,
        "maxheight": 80
    },
    "members": [teamMemberModelSchema]
}, { collection: 'team' });

teamModelSchema.set('collection', 'team');
mongoose.model('team', teamModelSchema)

And the approach that I am trying is the following:

module.exports.removeMember = function (req, res) {
  const email = req.params.email;
  const query = { "members.email": email };
  const pull = { $pull: { "members.$.email": email } };

  try {
    var message = teamMsg.teamMemberRemoveSuccess;

    TeamModel.updateOne(query, pull);

    responseUtilities.sendJSON(res, false, { message: message });
  } catch (err) {
    console.log(err.message);
    responseUtilities.sendJSON(res, err, { message: err.message });
  }
};

It executes with no errors, but nothing is updated.

I have tried some others alternatives with "FindOneAndUpdate" and "FindOneAndRemove" but, I could not find a solution.

Any ideas?

3 Answers

give this query a try:

db.collection.update(
    { 'members.email': 'email@address' },
    { $pull: { members: { email: 'email@address' } } },
    { multi: true }
)

You can use findOneAndUpdate with $pull operator for this task.

For removing items from an array of documents you can check MongoDb docs

You need to use await or then block to query. I used await, and made the function asynchronous by adding async keyword. We also need empty query object.

I also added the new: true option, to return the updated object to check if the item is deleted.

You need to handle the case where no document matches, I added a TODO for you.

module.exports.removeMember = async function(req, res) {
  const email = req.params.email;
  const query = {};

  const pull = {
    $pull: {
      members: {
        email: email
      }
    }
  };

  const options = {
    new: true
  };

  try {
    var message = teamMsg.teamMemberRemoveSuccess;

    const result = await TeamModel.updateOne(query, pull, options);

    console.log(result);

    if (!result) {
      //TODO: return 400-Bad Request or 404 - Not Found
    } else {
      responseUtilities.sendJSON(res, false, { message: message });
    }
  } catch (err) {
    console.log(err.message);
    responseUtilities.sendJSON(res, err, { message: err.message });
  }
};

Try using the update() method and async/await:

module.exports.removeMember = async function (req, res) {

    const email = req.params.email;
    console.log(`email = ${email}`)   // Make sure correct value is coming thru

    const query = { "members.email": email };
    const pull = { $pull: { "members.$.email": email } };
    const options = { multi: true }

    try {

        var message = teamMsg.teamMemberRemoveSuccess;

        await TeamModel.update( query, pull, options );


        responseUtilities.sendJSON(res, false, { "message": message });

    } catch (err) {
        console.log(err.message);
        responseUtilities.sendJSON(res, err, { "message": err.message });
    }
};
Related