MongoDB: How $pull works

25 Jan 2014

TLDR;

$pull is just an update. So the pulling happens only on the documents returned by the query part of update

Some background first. The $pull operator in MongoDB is used in conjunction with the update command to remove (or pull out) elements from an array.

The syntax for an update command is

db.collection.update(
  { /* find query */ },
  { /* new value */ }
);

Copied from the official documentation :

{ flags: ['vme', 'de', 'pse', 'tsc', 'msr', 'pae', 'mce' ] }

The following operation will remove the msr value from the flags array:
db.cpuinfo.update( { flags: 'msr' }, { $pull: { flags: 'msr' } } )

Personally, I had a hard time understanding the necessity of the first part of the update command in this case. If the values equallying ‘msr’ are going to be pulled for the key equallying ‘flags’, then why repeat the same in the query part?

Although the documentation is not incorrect, the oversimplified example makes it deceptive. The $pull operator is does not come into play, till the query part returns any documents. In other words, keep in mind that this is just an extension to update. So, don’t think about the pull till the query part is satisfied by at least one document in the collection.

For e.g.,

db.students.insert({
    name: 'Bob',
    grades: ['low', 'high']
});
db.students.insert({
    name: 'Mom',
    grades: ['low', 'average']
});

Now, although the $pull part in the following query would seem to satisfy both the documents, the grade ‘low’ will be removed only from ‘Mom’.

db.students.update(
    { name: 'Mom' }, 
    { $pull: {grades: 'low'} }
);

Edit