Alexander Mills
Alexander Mills

Reputation: 99960

Use mongoose / mongodb to $pull nested data from an array

say I have this array property ('articles') on a Mongoose schema:

articles: [ 

 {
  kind: 'bear',
  hashtag: 'foo'    
 },

 {
  kind: 'llama',
  hashtag: 'baz',
  },

 {
  kind: 'sheep',
  hashtag: 'bar',
  }

]

how can I use

$pull https://docs.mongodb.org/manual/reference/operator/update/pull/

to remote objects from this array by checking the value of hashtag to see if it matches a pattern?

For example, if I want to remove an object in the articles array where hashtag='foo'.

My best guess is the following, but it doesn't seem to work:

   var data = {
        "$pull": {
            "articles": {
                "$elemMatch": {
                    "hashtag": "foo"
                }
            }
        }
    };

Model.update({},data);  //doesn't quite work

this one seems to work:

   var data = {
        "$pull": {
            "articles": {
                "hashtag": 'foo'
            }
        }
    };

 Model.update({},data);  //seems to work

if you have a better solution or if you can show an alternate solution please provide an answer thank you

Upvotes: 1

Views: 1121

Answers (1)

Blakes Seven
Blakes Seven

Reputation: 50406

The $pull operator is basically a "mini query" in itself, and as such operators like $elemMatch become irrelevant as the "query" is directly performed on each array member anyway.

As such:

Model.update(
   {},
   { "$pull": { "articles": { "hashtag": "foo" }},
   { "multi": true },
   function(err,numAffected) {
       // handle result here
   }
)

So it is looking for the matching properties within the ( correct ) specified array in all array documents, and then removing them where there is a match.

The .update() also just returns the number of affected documents, and is usually used with { "multi": true } when you expect more than one document to be updated.

If you are just looking for "one" document, or expect the modified document in response, then use .findOneAndUpdate() instead:

Model.findOneAndUpdate(
   {},
   { "$pull": { "articles": { "hashtag": "foo" }},
   { "new": true },
   function(err,numAffected) {
       // handle result here
   }
)

Though not really practical without any selection criteria, since this just updates the first document found in the collection.

Upvotes: 2

Related Questions