29

I have a collection in MongoDB, which is like following:

{
    "_id" : "5327010328645530500",
    "members" : [
        {
            "participationCoeff" : 1,
            "tweetID" : "5327010328645530500"
        },
        {
            "participationCoeff" : 1,
            "tweetID" : "2820402625046999289"
        },
        {
            "participationCoeff" : 0.6666666666666666,
            "tweetID" : "6122060484520699114"
        },
        {
            "participationCoeff" : 1,
            "tweetID" : "4656669980325872747"
        }
    ]
}
{
    "_id" : "2646953848367646922",
    "members" : [
        {
            "participationCoeff" : 1,
            "tweetID" : "2646953848367646922"
        },
        {
            "participationCoeff" : 0.75,
            "tweetID" : "7750833069621794130"
        },
        {
            "participationCoeff" : 0.5,
            "tweetID" : "6271782334664128453"
        }
    ]
}

Basically, collection have clusters, where a cluster has an _id field and a members field. Members field is an array of documents, having following format.

{
            "participationCoeff" : 1,
            "tweetID" : "5327010328645530500"
        }

Now, from time to time, I have to delete these sub-documents in members attribute of cluster document, by matching tweetID.

However, I'm not able to find a query to achieve this effect. Basically, a tweetID will participate in many clusters, and hence will appear in multiple sub-documents of 'members' attribute of various clusters. I want to supply a bulk $pull operation, where I can remove all the sub-documents in all the clusters (i.e. their members attribute) which match on a particular tweetID.

Some help and intuition will be really helpful.

4 Answers 4

49

That's exactly what the $pull operator does, so in the shell you could use an update like:

db.clusters.update({}, 
    {$pull: {members: {tweetID: '5327010328645530500'}}}, 
    {multi: true})

Set the multi option so that every document is updated, not just the first one.

Sign up to request clarification or add additional context in comments.

5 Comments

getting following error. Cannot apply $pull/$pullAll modifier to non-array
@VaidAbhishek That means that you have some docs in the collection where members isn't an array.
I don't think that is the case with my collection. members will be a strictly array type attribute of cluster. Is there any way of doing this using aggregation!
@VaidAbhishek Are you sure? Even if members is null in a doc that would cause this error as that's not an array.
I don't think that is the case :-(
11

This will delete multiple tweets in a single query just pass an array to $in:-

db.clusters.update({}, 
{$pull: {members: {$in: [ {tweetID: '5327010328645530500'},{"tweetID" : "2820402625046999289"} ] } } }, 
{multi: true});

The above method doesnt work in mongoose so for mongoose do:-

 db.clusters.update({}, 
{$pull: {members:[ {tweetID: '5327010328645530500'},{"tweetID" : "2820402625046999289"} ]  } });

Comments

4

In the meantime the update method is deprecated. Therefore one possible up-to-date solution to this would be using the updateMany method instead.

db.clusters.updateMany({}, 
    {$pull: {members: {tweetID: '5327010328645530500'}}})

Comments

3

NOTE: Used in "mongoose": "^5.12.13".

As for today June 22nd, 2021, you can use $in and $pull mongodb operators to remove items from an array of documents :

Parent Document :

{
    "name": "June Grocery",
    "description": "Remember to pick Ephraim's favorit milk",
    "createdDate": "2021-06-09T20:17:29.029Z",
    "_id": "60c5f64f0041190ad312b419",
    "items": [],
    "budget": 1500,
    "owner": "60a97ea7c4d629866c1d99d1",
}

Documents in Items array :

{
    "category": "Fruits",
    "bought": false,
    "id": "60ada26be8bdbf195887acc1",
    "name": "Kiwi",
    "price": 0,
    "quantity": 1
},
{
    "category": "Toiletry",
    "bought": false,
    "id": "60b92dd67ae0934c8dfce126",
    "name": "Toilet Paper",
    "price": 0,
    "quantity": 1
},
{
    "category": "Toiletry",
    "bought": false,
    "id": "60b92fe97ae0934c8dfce127",
    "name": "Toothpaste",
    "price": 0,
    "quantity": 1
},
{
    "category": "Toiletry",
    "bought": false,
    "id": "60b92ffb7ae0934c8dfce128",
    "name": "Mouthwash",
    "price": 0,
    "quantity": 1
},
{
    "category": "Toiletry",
    "bought": false,
    "id": "60b931fa7ae0934c8dfce12d",
    "name": "Body Soap",
    "price": 0,
    "quantity": 1
},
{
    "category": "Fruit",
    "bought": false,
    "id": "60b9300c7ae0934c8dfce129",
    "name": "Banana",
    "price": 0,
    "quantity": 1
},
{
    "category": "Vegetable",
    "bought": false,
    "id": "60b930347ae0934c8dfce12a",
    "name": "Sombe",
    "price": 0,
    "quantity": 1
},

Query :

MyModel.updateMany(
    { _id: yourDocumentId },
    { $pull: { items: { id: { $in: itemIds } } } },
    { multi: true }
);

Note: ItemIds is an array of ObjectId. See below :

[
  '60ada26be8bdbf195887acc1',
  '60b930347ae0934c8dfce12a',
  '60b9300c7ae0934c8dfce129'
] 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.