diff --git a/lib/model.js b/lib/model.js index 5c4e9c8..54de2c9 100755 --- a/lib/model.js +++ b/lib/model.js @@ -272,12 +272,31 @@ lastStepModifierFunctions.$push = function (obj, field, value) { if (!util.isArray(obj[field])) { throw new Error("Can't $push an element on non-array values"); } if (value !== null && typeof value === 'object' && value.$each) { - if (Object.keys(value).length > 1) { throw new Error("Can't use another field in conjunction with $each"); } + var keys = Object.keys(value); + if (keys.length > 1 && keys.sort()[1] !== '$slice') { + throw new Error("Can't use another field in conjunction with $each"); } if (!util.isArray(value.$each)) { throw new Error("$each requires an array value"); } value.$each.forEach(function (v) { obj[field].push(v); }); + + var slice = parseInt(value.$slice, 10); + if (!isNaN(slice)) { + if (slice === 0) { + obj[field] = []; + } else { + var start, end, n = obj[field].length; + if (slice < 0) { + start = Math.max(0, n + slice); + end = n; + } else if (slice > 0) { + start = 0; + end = Math.min(n, slice); + } + obj[field] = obj[field].slice(start, end); + } + } } else { obj[field].push(value); } diff --git a/test/model.test.js b/test/model.test.js index 77976dd..a91ef03 100755 --- a/test/model.test.js +++ b/test/model.test.js @@ -520,6 +520,35 @@ describe('Model', function () { }).should.throw(); }); + it('Can use the $slice modifier to limits the number of array elements', function () { + var obj = { arr: ['hello'] } + , modified; + + modified = model.modify(obj, { $push: { arr: { $each: ['world', 'earth', 'everything'], $slice: 1 } } }); + assert.deepEqual(modified, { arr: ['hello'] }); + + modified = model.modify(obj, { $push: { arr: { $each: ['world', 'earth', 'everything'], $slice: -1 } } }); + assert.deepEqual(modified, { arr: ['everything'] }); + + modified = model.modify(obj, { $push: { arr: { $each: ['world', 'earth', 'everything'], $slice: 0 } } }); + assert.deepEqual(modified, { arr: [] }); + + modified = model.modify(obj, { $push: { arr: { $each: ['world', 'earth', 'everything'], $slice: 2 } } }); + assert.deepEqual(modified, { arr: ['hello', 'world'] }); + + modified = model.modify(obj, { $push: { arr: { $each: ['world', 'earth', 'everything'], $slice: -2 } } }); + assert.deepEqual(modified, { arr: ['earth', 'everything'] }); + + modified = model.modify(obj, { $push: { arr: { $each: ['world', 'earth', 'everything'], $slice: -20 } } }); + assert.deepEqual(modified, { arr: ['hello', 'world', 'earth', 'everything'] }); + + modified = model.modify(obj, { $push: { arr: { $each: ['world', 'earth', 'everything'], $slice: 20 } } }); + assert.deepEqual(modified, { arr: ['hello', 'world', 'earth', 'everything'] }); + + modified = model.modify(obj, { $push: { arr: { $each: [], $slice: 1 } } }); + assert.deepEqual(modified, { arr: ['hello'] }); + }); + }); // End of '$push modifier' describe('$addToSet modifier', function () {