Added support for $pull operator

pull/2/head
Jakub Szwacz 11 years ago
parent bd7798aa89
commit d834b9c3a7
  1. 8
      README.md
  2. 16
      lib/model.js
  3. 45
      test/model.test.js

@ -264,7 +264,7 @@ db.count({}, function (err, count) {
* `query` is the same kind of finding query you use with `find` and `findOne`
* `update` specifies how the documents should be modified. It is either a new document or a set of modifiers (you cannot use both together, it doesn't make sense!)
* A new document will replace the matched docs
* The modifiers create the fields they need to modify if they don't exist, and you can apply them to subdocs. Available field modifiers are `$set` to change a field's value, `$unset` to delete a field and `$inc` to increment a field's value. To work on arrays, you have `$push`, `$pop`, `$addToSet`, and the special `$each`. See examples below for the syntax.
* The modifiers create the fields they need to modify if they don't exist, and you can apply them to subdocs. Available field modifiers are `$set` to change a field's value, `$unset` to delete a field and `$inc` to increment a field's value. To work on arrays, you have `$push`, `$pop`, `$addToSet`, `$pull`, and the special `$each`. See examples below for the syntax.
* `options` is an object with two possible parameters
* `multi` (defaults to `false`) which allows the modification of several documents if set to true
* `upsert` (defaults to `false`) if you want to insert a new document corresponding to the `update` rules if your `query` doesn't match anything
@ -350,6 +350,12 @@ db.update({ _id: 'id6' }, { $addToSet: { fruits: 'apple' } }, {}, function () {
// If we had used a fruit not in the array, e.g. 'banana', it would have been added to the array
});
// $pull removes all instances of a value from an existing array
// Equality is deep-checked
db.update({ _id: 'id6' }, { $pull: { fruits: 'apple' } }, {}, function () {
// Now the fruits array is ['orange', 'pear']
});
// $each can be used to $push or $addToSet multiple values at once
// This example works the same way with $addToSet
db.update({ _id: 'id6' }, { $push: { fruits: ['banana', 'orange'] } }, {}, function () {

@ -306,6 +306,22 @@ lastStepModifierFunctions.$pop = function (obj, field, value) {
};
/**
* Removes all instances of a value from an existing array
*/
lastStepModifierFunctions.$pull = function (obj, field, value) {
var arr, i;
if (!util.isArray(obj[field])) { throw "Can't $pull an element from non-array values"; }
arr = obj[field];
for (i = arr.length - 1; i >= 0; i -= 1) {
if (_.isEqual(arr[i], value)) {
arr.splice(i, 1);
}
}
};
/**
* Increment a numeric field's value
*/

@ -541,6 +541,51 @@ describe('Model', function () {
}); // End of '$pop modifier'
describe('$pull modifier', function () {
it('Can remove an element from a set', function () {
var obj = { arr: ['hello', 'world'] }
, modified;
modified = model.modify(obj, { $pull: { arr: 'world' } });
assert.deepEqual(modified, { arr: ['hello'] });
obj = { arr: ['hello'] };
modified = model.modify(obj, { $pull: { arr: 'world' } });
assert.deepEqual(modified, { arr: ['hello'] });
});
it('Can remove multiple matching elements', function () {
var obj = { arr: ['hello', 'world', 'hello', 'world'] }
, modified;
modified = model.modify(obj, { $pull: { arr: 'world' } });
assert.deepEqual(modified, { arr: ['hello', 'hello'] });
});
it('Throw if we try to pull from a non-array', function () {
var obj = { arr: 'hello' }
, modified;
(function () {
modified = model.modify(obj, { $pull: { arr: 'world' } });
}).should.throw();
});
it('Use deep-equality to check whether we can remove a value from a set', function () {
var obj = { arr: [{ b: 2 }, { b: 3 }] }
, modified;
modified = model.modify(obj, { $pull: { arr: { b: 3 } } });
assert.deepEqual(modified, { arr: [ { b: 2 } ] });
obj = { arr: [ { b: 2 } ] }
modified = model.modify(obj, { $pull: { arr: { b: 3 } } });
assert.deepEqual(modified, { arr: [{ b: 2 }] });
});
}); // End of '$pull modifier'
}); // ==== End of 'Modifying documents' ==== //

Loading…
Cancel
Save