From 44316c26fcd0f45275093d16e0707bab07279ee4 Mon Sep 17 00:00:00 2001 From: Evgenia Date: Tue, 2 Feb 2016 15:35:57 +0200 Subject: [PATCH] db.update $min $max operators --- README.md | 14 ++++++++- lib/model.js | 16 +++++++++++ test/model.test.js | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 171dd35..f5c6726 100755 --- a/README.md +++ b/README.md @@ -432,7 +432,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`, `$pull`, and the special `$each` and `$slice`. 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, `$inc` to increment a field's value and `$min`, `$max` to check if specified field is smaller or is greater than the current value of the field. To work on arrays, you have `$push`, `$pop`, `$addToSet`, `$pull`, and the special `$each` and `$slice`. 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. If your `update` is a simple object with no modifiers, it is the inserted document. In the other case, the `query` is stripped from all operator recursively, and the `update` is applied to it. @@ -540,6 +540,18 @@ db.update({ _id: 'id6' }, { $push: { fruits: { $each: ['banana', 'orange'] } } } db.update({ _id: 'id6' }, { $push: { fruits: { $each: ['banana'], $slice: 2 } } }, {}, function () { // Now the fruits array is ['apple', 'orange'] }); + +// Update the value of the field, only if specified field is smaller or greater than the current value of the field +// Let's say the database contains this document +// doc = { _id: 'id1', name: 'Name', value: 5 } +// $min can be used to update field if current value is greater than the specified value +db.update({ _id: 'id1' }, { $min: { value: 2 } }, {}, function () { + // The document will be updated to { _id: 'id1', name: 'Name', value: 2 } +}); +// $max can be used to update field if current value is smaller than the specified value +db.update({ _id: 'id1' }, { $max: { value: 8 } }, {}, function () { + // The document will be updated to { _id: 'id1', name: 'Name', value: 8 } +}); ``` ### Removing documents diff --git a/lib/model.js b/lib/model.js index 8845bf8..8e7fd74 100755 --- a/lib/model.js +++ b/lib/model.js @@ -386,6 +386,22 @@ lastStepModifierFunctions.$inc = function (obj, field, value) { } }; +/** + * Updates the value of the field, only if specified field is greater than the current value of the field + */ +lastStepModifierFunctions.$max = function (obj, field, value) { + if (typeof obj[field] === 'undefined') obj[field] = value; + else if (value > obj[field]) obj[field] = value; +}; + +/** + * Updates the value of the field, only if specified field is smaller than the current value of the field + */ +lastStepModifierFunctions.$min = function (obj, field, value) { + if (typeof obj[field] === 'undefined') obj[field] = value; + else if (value < obj[field]) obj[field] = value; +}; + // Given its name, create the complete modifier function function createModifierFunction (modifier) { return function (obj, field, value) { diff --git a/test/model.test.js b/test/model.test.js index 5f81723..f13bf2a 100755 --- a/test/model.test.js +++ b/test/model.test.js @@ -725,6 +725,78 @@ describe('Model', function () { }); // End of '$pull modifier' + describe('$max modifier', function () { + it('Will set the field to the updated value if value is greater than current one, without modifying the original object', function () { + var obj = { some:'thing', number: 10} + , updateQuery = {$max:{number:12}} + , modified = model.modify(obj,updateQuery); + + modified.should.deep.equal({some:'thing',number:12}); + + obj.should.deep.equal({some:'thing', number:10}); + }); + + it('Will not update the field if new value is smaller than current one', function () { + var obj = { some:'thing', number: 10} + , updateQuery = {$max:{number:9}} + , modified = model.modify(obj,updateQuery); + + modified.should.deep.equal({some:'thing',number:10}); + }); + + it('Will create the field if it does not exist', function () { + var obj = {some:'thing'} + , updateQuery = {$max:{number:10}} + , modified = model.modify(obj,updateQuery); + + modified.should.deep.equal({some:'thing', number:10}); + }); + + it('Works on embedded documents', function () { + var obj = {some:'thing', somethingElse:{number:10}} + , updateQuery = {$max:{'somethingElse.number':12}} + , modified = model.modify(obj,updateQuery); + + modified.should.deep.equal({some:'thing',somethingElse:{number:12}}); + }); + });// End of '$max modifier' + + describe('$min modifier', function () { + it('Will set the field to the updated value if value is smaller than current one, without modifying the original object', function () { + var obj = { some:'thing', number: 10} + , updateQuery = {$min:{number:8}} + , modified = model.modify(obj,updateQuery); + + modified.should.deep.equal({some:'thing',number:8}); + + obj.should.deep.equal({some:'thing', number:10}); + }); + + it('Will not update the field if new value is greater than current one', function () { + var obj = { some:'thing', number: 10} + , updateQuery = {$min:{number:12}} + , modified = model.modify(obj,updateQuery); + + modified.should.deep.equal({some:'thing',number:10}); + }); + + it('Will create the field if it does not exist', function () { + var obj = {some:'thing'} + , updateQuery = {$min:{number:10}} + , modified = model.modify(obj,updateQuery); + + modified.should.deep.equal({some:'thing', number:10}); + }); + + it('Works on embedded documents', function () { + var obj = {some:'thing', somethingElse:{number:10}} + , updateQuery = {$min:{'somethingElse.number':8}} + , modified = model.modify(obj,updateQuery); + + modified.should.deep.equal({some:'thing',somethingElse:{number:8}}); + }); + });// End of '$min modifier' + }); // ==== End of 'Modifying documents' ==== //