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.

VaidAbhishek
  • 5,895
  • 7
  • 43
  • 59

4 Answers4

47

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.

JohnnyHK
  • 305,182
  • 66
  • 621
  • 471
10

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"} ]  } });
Shrabanee
  • 2,706
  • 1
  • 18
  • 30
Amit Kumar
  • 407
  • 5
  • 7
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'}}})
stefano
  • 315
  • 2
  • 16
2

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'
] 
elena.kim
  • 930
  • 4
  • 12
  • 22