psiphi75
psiphi75

Reputation: 2065

Mongoose deleting (pull) a document within an array, does not work with ObjectID

I have the following mongoose schema:

user = {
    "userId" : "myId",
    "connections":
    [{
        "dateConnectedUnix": 1334567891,
        "isActive": true
    }, {
        "dateConnectedUnix": 1334567893,
        "isActive": false
    }]
}

I would like to delete the second item in the connections array, to get the following:

user = {
    "userId" : "myId",
    "connections": 
    [{
        "dateConnectedUnix": 1334567893,
        "isActive": false
    }]
}

The following code does the job as expected:

userAccounts.update(
    { 'connections.isActive': false }, 
    { $pull: { 'connections.isActive':false }}, 
    function (err, val) {
        console.log(val)
    }
);

But, I need to delete based on ObjectId. And the following goes does not work:

userAccounts.update(
    { 'connections._id': '1234-someId-6789' }, 
    { $pull: { 'connections._id': '1234-someId-6789' } },
    function (err, val) {
        console.log(val)
    }
);

Any suggestions? I have been banging my head against the screen (aka Google, Stackoverflow, ...) for hours and have had no luck.

Upvotes: 39

Views: 76636

Answers (10)

Diego Felipe
Diego Felipe

Reputation: 391

In case some is struggling with $pull operator my problem was that I forgot to add the nested array inside the schema, so Mongoose can't recognize it and delete it.

Upvotes: 0

Phuong Tran
Phuong Tran

Reputation: 1

Note: If you use the pull method with syntax: $pull: {propertyId: _id} with _id can be found from a document, ensure that _id is string type if not using the method toString() to convert to string type. Let's check it!

Upvotes: 0

WasiF
WasiF

Reputation: 28847

use findByIdAndUpdate to remove an item from an array

You can do it in mongoose 5.4.x and above

const result = await User.findByIdAndUpdate(user_id, {
    $pull: {
        someArrayName: { _id: array_item_id }
    }
}, { new: true });

The item from array will be removed based on provided property _id value

Upvotes: 7

kengres
kengres

Reputation: 430

If you are using mongoose, no need to use the MongoDB stuff, I mean that's why we're using mongoose in the first place, right?

userAccounts.connections.pull({ _id: '1234-someId-6789'});
await userAccounts.save();

Upvotes: 3

throrin19
throrin19

Reputation: 18197

To use update with ObjectId, you should use ObjectId object instead of string representation :

var ObjectId = require('mongoose').Types.ObjectId;

userAccounts.update(
    { 'connections._id': new ObjectId('1234-someId-6789') }, 
    { $pull: { 'connections._id': new ObjectId('1234-someId-6789') } }, 
    function (err,val) {
        console.log(val)
    }
);

Upvotes: 10

Deepak Sisodiya
Deepak Sisodiya

Reputation: 848

I have a document like

enter image description here

I have to delete address from address array

After searching lots on internet I found the solution

Customer.findOneAndUpdate(query, {$pull: {address: addressId}}, (err, data) => {
    if (err) {
        return res.status(500).json({ error: 'error in deleting address' });
    }
    res.json(data);   
});

Upvotes: 22

psiphi75
psiphi75

Reputation: 2065

It seems that the above code would not work. It should not even have worked for the first example I gave.

In the end I was supported by this answer here: MongoDB, remove object from array

Here is my working code:

userAccounts.update( 
    { userId: usr.userId },
    {
        $pull: {
            connections: { _id : connId }
        }
    },
    { safe: true },
    function removeConnectionsCB(err, obj) {
        // ...
    }
);

Upvotes: 55

biscarrosse
biscarrosse

Reputation: 121

In mongoose 5.8.11, this $pull: { ... } didn't work for me, so far not sure why. So I overcame it in my controller this way:

exports.removePost = async (req, res, next) => {
  const postId = req.params.postId;
  try {
    const foundPost = await Post.findById(postId);
    const foundUser = await User.findById(req.userId);
    if (!foundPost || !foundUser) {
      const err = new Error(
        'Could not find post / user.',
      );
      err.statusCode = 404;
      throw err;
    }
    // delete post from posts collection:
    await Post.findByIdAndRemove(postId);
    // also delete that post from posts array of id's in user's collection:
    foundUser.posts.pull({ _id: postId });
    await foundUser.save();
    res.status(200).json({ message: 'Deleted post.' });
  } catch (err) {
    // ...
  }
};

Upvotes: 1

uak
uak

Reputation: 85

user: {
 _id: ObjectId('5ccf3fa47a8f8b12b0dce204'),
 name: 'Test',
 posts: [
  ObjectId("5cd07ee05c08f51af8d23b64"),
  ObjectId("5cd07ee05c08f51af8d23c52")
 ]
}

Remove a single post from posts array

user.posts.pull("5cd07ee05c08f51af8d23b64"); user.save();

Upvotes: 11

chenop
chenop

Reputation: 5143

mongoose: 4.11.11
What have worked for me is the following syntax:

const removeTansactionFromUser = (userId, connectionId) => {
    return User.findByIdAndUpdate(userId, { $pull: { "connections": connectionId} }, {'new': true} );
};

Mongoose support id in string format or ObjectId format.
Tip: new ObjectId(stringId) to switch from string to ObjectId

Upvotes: 1

Related Questions