Dot notation is now able to go inside arrays and array indexes

pull/2/head
Louis Chatriot 11 years ago
parent 4ff94fa1bf
commit 74ac0bae62
  1. 2
      benchmarks/commonUtilities.js
  2. 28
      lib/model.js
  3. 41
      test/model.test.js

@ -124,7 +124,7 @@ module.exports.findDocs = function (d, n, profiler, cb) {
function runFrom(i) { function runFrom(i) {
if (i === n) { // Finished if (i === n) { // Finished
console.log("===== RESULT (find with in selector) ===== " + Math.floor(1000* n / profiler.elapsedSinceLastStep()) + " ops/s"); console.log("===== RESULT (find) ===== " + Math.floor(1000* n / profiler.elapsedSinceLastStep()) + " ops/s");
profiler.step('Finished finding ' + n + ' docs'); profiler.step('Finished finding ' + n + ' docs');
return cb(); return cb();
} }

@ -435,18 +435,28 @@ function modify (obj, updateQuery) {
* @param {String} field * @param {String} field
*/ */
function getDotValue (obj, field) { function getDotValue (obj, field) {
var fieldParts = typeof field === 'string' ? field.split('.') : field; var fieldParts = typeof field === 'string' ? field.split('.') : field
, i, objs;
if (!obj) { return undefined; } // field cannot be empty so that means we should return undefined so that nothing can match if (!obj) { return undefined; } // field cannot be empty so that means we should return undefined so that nothing can match
if (fieldParts.length === 1) { if (fieldParts.length === 0) { return obj; }
return obj[fieldParts[0]];
} else if (util.isArray(obj[fieldParts[0]])) { if (fieldParts.length === 1) { return obj[fieldParts[0]]; }
var objs = new Array();
for (var i = 0; i < obj[fieldParts[0]].length; i += 1) { if (util.isArray(obj[fieldParts[0]])) {
objs = objs.concat(getDotValue(obj[fieldParts[0]][i], fieldParts.slice(1).join('.'))); // If the next field is an integer, return only this item of the array
} i = parseInt(fieldParts[1], 10);
return objs; if (typeof i === 'number' && !isNaN(i)) {
return getDotValue(obj[fieldParts[0]][i], fieldParts.slice(2))
}
// Return the array of values
objs = new Array();
for (i = 0; i < obj[fieldParts[0]].length; i += 1) {
objs.push(getDotValue(obj[fieldParts[0]][i], fieldParts.slice(1)));
}
return objs;
} else { } else {
return getDotValue(obj[fieldParts[0]], fieldParts.slice(1)); return getDotValue(obj[fieldParts[0]], fieldParts.slice(1));
} }

@ -840,6 +840,43 @@ describe('Model', function () {
assert.isUndefined(model.getDotValue({ hello: 'world' }, 'helloo')); assert.isUndefined(model.getDotValue({ hello: 'world' }, 'helloo'));
assert.isUndefined(model.getDotValue({ hello: 'world', type: { planet: true } }, 'type.plane')); assert.isUndefined(model.getDotValue({ hello: 'world', type: { planet: true } }, 'type.plane'));
}); });
it("Can navigate inside arrays with dot notation, and return the array of values in that case", function () {
var dv;
// Simple array of subdocuments
dv = model.getDotValue({ planets: [ { name: 'Earth', number: 3 }, { name: 'Mars', number: 2 }, { name: 'Pluton', number: 9 } ] }, 'planets.name');
assert.deepEqual(dv, ['Earth', 'Mars', 'Pluton']);
// Nested array of subdocuments
dv = model.getDotValue({ nedb: true, data: { planets: [ { name: 'Earth', number: 3 }, { name: 'Mars', number: 2 }, { name: 'Pluton', number: 9 } ] } }, 'data.planets.number');
assert.deepEqual(dv, [3, 2, 9]);
// Nested array in a subdocument of an array (yay, inception!)
// TODO: make sure MongoDB doesn't flatten the array (it wouldn't make sense)
dv = model.getDotValue({ nedb: true, data: { planets: [ { name: 'Earth', numbers: [ 1, 3 ] }, { name: 'Mars', numbers: [ 7 ] }, { name: 'Pluton', numbers: [ 9, 5, 1 ] } ] } }, 'data.planets.numbers');
assert.deepEqual(dv, [[ 1, 3 ], [ 7 ], [ 9, 5, 1 ]]);
});
it("Can get a single value out of an array using its index", function () {
var dv;
// Simple index in dot notation
dv = model.getDotValue({ planets: [ { name: 'Earth', number: 3 }, { name: 'Mars', number: 2 }, { name: 'Pluton', number: 9 } ] }, 'planets.1');
assert.deepEqual(dv, { name: 'Mars', number: 2 });
// Out of bounds index
dv = model.getDotValue({ planets: [ { name: 'Earth', number: 3 }, { name: 'Mars', number: 2 }, { name: 'Pluton', number: 9 } ] }, 'planets.3');
assert.isUndefined(dv);
// Index in nested array
dv = model.getDotValue({ nedb: true, data: { planets: [ { name: 'Earth', number: 3 }, { name: 'Mars', number: 2 }, { name: 'Pluton', number: 9 } ] } }, 'data.planets.2');
assert.deepEqual(dv, { name: 'Pluton', number: 9 });
// Dot notation with index in the middle
dv = model.getDotValue({ nedb: true, data: { planets: [ { name: 'Earth', number: 3 }, { name: 'Mars', number: 2 }, { name: 'Pluton', number: 9 } ] } }, 'data.planets.0.name');
dv.should.equal('Earth');
});
}); });
@ -1059,8 +1096,8 @@ describe('Model', function () {
model.match({ childrens: [] }, { "childrens": { $size: 3 } }).should.equal(false); model.match({ childrens: [] }, { "childrens": { $size: 3 } }).should.equal(false);
}); });
it.only('Should throw an error if a query operator is used without being applied to an array and comparing to an integer', function () { it('Should throw an error if a query operator is used without being applied to an array and comparing to an integer', function () {
model.match({ a: 5 }, { a: { $size: 1 } }); // model.match({ a: 5 }, { a: { $size: 1 } });
(function () { model.match({ a: [1, 5] }, { a: { $size: 1.4 } }); }).should.throw(); (function () { model.match({ a: [1, 5] }, { a: { $size: 1.4 } }); }).should.throw();
(function () { model.match({ a: [1, 5] }, { a: { $size: 'fdf' } }); }).should.throw(); (function () { model.match({ a: [1, 5] }, { a: { $size: 'fdf' } }); }).should.throw();
}); });

Loading…
Cancel
Save