Comparing version 0.10.7 to 0.10.9
@@ -0,0 +0,0 @@ /** |
@@ -0,0 +0,0 @@ var Datastore = require('../lib/datastore') |
@@ -0,0 +0,0 @@ var Datastore = require('../lib/datastore') |
@@ -0,0 +0,0 @@ var Datastore = require('../lib/datastore') |
@@ -0,0 +0,0 @@ var Datastore = require('../lib/datastore') |
@@ -0,0 +0,0 @@ var Datastore = require('../lib/datastore') |
@@ -0,0 +0,0 @@ var Datastore = require('../lib/datastore') |
@@ -0,0 +0,0 @@ var Datastore = require('../lib/datastore') |
@@ -0,0 +0,0 @@ var Datastore = require('../lib/datastore') |
@@ -0,0 +0,0 @@ /** |
@@ -0,0 +0,0 @@ /** |
@@ -0,0 +0,0 @@ /** |
@@ -0,0 +0,0 @@ { |
@@ -0,0 +0,0 @@ /** |
var Datastore = require('./lib/datastore'); | ||
module.exports = Datastore; |
/** | ||
* Manage access to data, be it to find, update or remove it | ||
*/ | ||
var model = require('./model'); | ||
var model = require('./model') | ||
, _ = require('underscore') | ||
; | ||
/** | ||
@@ -12,3 +14,3 @@ * Create a new cursor for this collection | ||
* @param {Query} query - The query this cursor will operate on | ||
* @param {Function} execDn - Handler to be executed after cursor has found the results and before the callback passed to find/findOne/update/remove | ||
* @param {Function} execDn - Handler to be executed after cursor has found the results and before the callback passed to find/findOne/update/remove | ||
*/ | ||
@@ -42,3 +44,3 @@ function Cursor (db, query, execFn) { | ||
* Sort results of the query | ||
* @Param {SortQuery} sortQuery - SortQuery is { field: order }, field can use the dot-notation, order is 1 for ascending and -1 for descending | ||
* @param {SortQuery} sortQuery - SortQuery is { field: order }, field can use the dot-notation, order is 1 for ascending and -1 for descending | ||
*/ | ||
@@ -52,2 +54,50 @@ Cursor.prototype.sort = function(sortQuery) { | ||
/** | ||
* Add the use of a projection | ||
* @param {Object} projection - MongoDB-style projection. {} means take all fields. Then it's { key1: 1, key2: 1 } to take only key1 and key2 | ||
* { key1: 0, key2: 0 } to omit only key1 and key2. Except _id, you can't mix takes and omits | ||
*/ | ||
Cursor.prototype.projection = function(projection) { | ||
this._projection = projection; | ||
return this; | ||
}; | ||
/** | ||
* Apply the projection | ||
*/ | ||
Cursor.prototype.project = function (candidates) { | ||
var res = [], self = this | ||
, keepId, action, keys | ||
; | ||
if (this._projection === undefined || Object.keys(this._projection).length === 0) { | ||
return candidates; | ||
} | ||
keepId = this._projection._id === 0 ? false : true; | ||
this._projection = _.omit(this._projection, '_id'); | ||
// Check for consistency | ||
keys = Object.keys(this._projection); | ||
keys.forEach(function (k) { | ||
if (action !== undefined && self._projection[k] !== action) { throw "Can't both keep and omit fields except for _id"; } | ||
action = self._projection[k]; | ||
}); | ||
// Do the actual projection | ||
candidates.forEach(function (candidate) { | ||
var toPush = action === 1 ? _.pick(candidate, keys) : _.omit(candidate, keys); | ||
if (keepId) { | ||
toPush._id = candidate._id; | ||
} else { | ||
delete toPush._id; | ||
} | ||
res.push(toPush); | ||
}); | ||
return res; | ||
}; | ||
/** | ||
* Get all matching elements | ||
@@ -62,5 +112,6 @@ * Will return pointers to matched elements (shallow copies), returning full copies is the role of find or findOne | ||
, res = [], added = 0, skipped = 0, self = this | ||
, error = null | ||
, i, keys, key | ||
; | ||
try { | ||
@@ -76,3 +127,3 @@ for (i = 0; i < candidates.length; i += 1) { | ||
added += 1; | ||
if (this._limit && this._limit <= added) { break; } | ||
if (this._limit && this._limit <= added) { break; } | ||
} | ||
@@ -91,3 +142,3 @@ } else { | ||
keys = Object.keys(this._sort); | ||
// Sorting | ||
@@ -110,14 +161,22 @@ var criteria = []; | ||
}); | ||
// Applying limit and skip | ||
var limit = this._limit || res.length | ||
, skip = this._skip || 0; | ||
res = res.slice(skip, skip + limit); | ||
} | ||
// Apply projection | ||
try { | ||
res = this.project(res); | ||
} catch (e) { | ||
error = e; | ||
res = undefined; | ||
} | ||
if (this.execFn) { | ||
return this.execFn(null, res, callback); | ||
return this.execFn(error, res, callback); | ||
} else { | ||
return callback(null, res); | ||
return callback(error, res); | ||
} | ||
@@ -133,2 +192,2 @@ }; | ||
// Interface | ||
module.exports = Cursor; | ||
module.exports = Cursor; |
@@ -0,0 +0,0 @@ var crypto = require('crypto') |
@@ -379,9 +379,23 @@ var customUtils = require('./customUtils') | ||
* @param {Object} query MongoDB-style query | ||
* @param {Object} projection MongoDB-style projection | ||
*/ | ||
Datastore.prototype.find = function (query, callback) { | ||
Datastore.prototype.find = function (query, projection, callback) { | ||
switch (arguments.length) { | ||
case 1: | ||
projection = {}; | ||
// callback is undefined, will return a cursor | ||
break; | ||
case 2: | ||
if (typeof projection === 'function') { | ||
callback = projection; | ||
projection = {}; | ||
} // If not assume projection is an object and callback undefined | ||
break; | ||
} | ||
var cursor = new Cursor(this, query, function(err, docs, callback) { | ||
var res = [], i; | ||
if (err) { return callback(err); } | ||
for (i = 0; i < docs.length; i += 1) { | ||
@@ -393,2 +407,3 @@ res.push(model.deepCopy(docs[i])); | ||
cursor.projection(projection); | ||
if (typeof callback === 'function') { | ||
@@ -405,4 +420,18 @@ cursor.exec(callback); | ||
* @param {Object} query MongoDB-style query | ||
* @param {Object} projection MongoDB-style projection | ||
*/ | ||
Datastore.prototype.findOne = function (query, callback) { | ||
Datastore.prototype.findOne = function (query, projection, callback) { | ||
switch (arguments.length) { | ||
case 1: | ||
projection = {}; | ||
// callback is undefined, will return a cursor | ||
break; | ||
case 2: | ||
if (typeof projection === 'function') { | ||
callback = projection; | ||
projection = {}; | ||
} // If not assume projection is an object and callback undefined | ||
break; | ||
} | ||
var cursor = new Cursor(this, query, function(err, docs, callback) { | ||
@@ -413,7 +442,7 @@ if (err) { return callback(err); } | ||
} else { | ||
return callback(null, null); | ||
return callback(null, null); | ||
} | ||
}); | ||
cursor.limit(1); | ||
cursor.projection(projection).limit(1); | ||
if (typeof callback === 'function') { | ||
@@ -554,2 +583,4 @@ cursor.exec(callback); | ||
module.exports = Datastore; |
@@ -0,0 +0,0 @@ /** |
@@ -0,0 +0,0 @@ var BinarySearchTree = require('binary-search-tree').AVLTree |
@@ -0,0 +0,0 @@ /** |
@@ -0,0 +0,0 @@ /** |
{ | ||
"name": "nedb", | ||
"version": "0.10.7", | ||
"version": "0.10.9", | ||
"author": { | ||
@@ -25,3 +25,3 @@ "name": "Louis Chatriot", | ||
"underscore": "~1.4.4", | ||
"binary-search-tree": "0.2.3", | ||
"binary-search-tree": "0.2.4", | ||
"mkdirp": "~0.3.5" | ||
@@ -28,0 +28,0 @@ }, |
@@ -38,2 +38,3 @@ # NeDB (Node embedded database) | ||
* <a href="#sorting-and-paginating">Sorting and paginating</a> | ||
* <a href="#projections">Projections</a> | ||
* <a href="#counting-documents">Counting documents</a> | ||
@@ -158,2 +159,4 @@ * <a href="#updating-documents">Updating documents</a> | ||
You can use standard projections to restrict the fields to appear in the results (see below). | ||
#### Basic querying | ||
@@ -342,4 +345,37 @@ Basic querying means are looking for documents whose fields match the ones you specify. You can use regular expression to match strings. | ||
#### Projections | ||
You can give `find` and `findOne` an optional second argument, `projections`. The syntax is the same as MongoDB: `{ a: 1, b: 1 }` to return only the `a` and `b` fields, `{ a: 0, b: 0 }` to omit these two fields. You cannot use both modes at the time, except for `_id` which is by default always returned and which you can choose to omit. | ||
```javascript | ||
// Same database as above | ||
// Keeping only the given fields | ||
db.find({ planet: 'Mars' }, { planet: 1, system: 1 }, function (err, docs) { | ||
// docs is [{ planet: 'Mars', system: 'solar', _id: 'id1' }] | ||
}); | ||
// Keeping only the given fields but removing _id | ||
db.find({ planet: 'Mars' }, { planet: 1, system: 1, _id: 0 }, function (err, docs) { | ||
// docs is [{ planet: 'Mars', system: 'solar' }] | ||
}); | ||
// Omitting only the given fields and removing _id | ||
db.find({ planet: 'Mars' }, { planet: 0, system: 0, _id: 0 }, function (err, docs) { | ||
// docs is [{ inhabited: false, satellites: ['Phobos', 'Deimos'] }] | ||
}); | ||
// Failure: using both modes at the same time | ||
db.find({ planet: 'Mars' }, { planet: 0, system: 1 }, function (err, docs) { | ||
// err is the error message, docs is undefined | ||
}); | ||
// You can also use it in a Cursor way but this syntax is not compatible with MongoDB | ||
// If upstream compatibility is important don't use this method | ||
db.find({ planet: 'Mars' }).projection({ planet: 1, system: 1 }).exec(function (err, docs) { | ||
// docs is [{ planet: 'Mars', system: 'solar', _id: 'id1' }] | ||
}); | ||
``` | ||
### Counting documents | ||
@@ -346,0 +382,0 @@ You can use `count` to count documents. It has the same syntax as `find`. For example: |
@@ -0,0 +0,0 @@ var Nedb = require('../lib/datastore.js') |
@@ -42,3 +42,3 @@ var should = require('chai').should() | ||
}); | ||
describe('Without sorting', function () { | ||
@@ -59,3 +59,3 @@ | ||
}); | ||
it('Without query, an empty query or a simple query and no skip or limit', function (done) { | ||
@@ -139,3 +139,3 @@ async.waterfall([ | ||
}); | ||
it('With a limit and a skip and method chaining', function (done) { | ||
@@ -151,6 +151,6 @@ var cursor = new Cursor(d); | ||
}); | ||
}); // ===== End of 'Without sorting' ===== | ||
describe('Sorting of the results', function () { | ||
@@ -172,3 +172,3 @@ | ||
}); | ||
it('Using one sort', function (done) { | ||
@@ -649,3 +649,3 @@ var cursor, i; | ||
docs.length.should.equal(60); | ||
for (var i = 0; i < docs.length; i++) { | ||
@@ -660,3 +660,126 @@ docs[i].nid.should.equal(i+1); | ||
}); // ===== End of 'Sorting' ===== | ||
describe('Projections', function () { | ||
var doc1, doc2, doc3, doc4, doc0; | ||
beforeEach(function (done) { | ||
// We don't know the order in which docs wil be inserted but we ensure correctness by testing both sort orders | ||
d.insert({ age: 5, name: 'Jo', planet: 'B' }, function (err, _doc0) { | ||
doc0 = _doc0; | ||
d.insert({ age: 57, name: 'Louis', planet: 'R' }, function (err, _doc1) { | ||
doc1 = _doc1; | ||
d.insert({ age: 52, name: 'Grafitti', planet: 'C' }, function (err, _doc2) { | ||
doc2 = _doc2; | ||
d.insert({ age: 23, name: 'LM', planet: 'S' }, function (err, _doc3) { | ||
doc3 = _doc3; | ||
d.insert({ age: 89, planet: 'Earth' }, function (err, _doc4) { | ||
doc4 = _doc4; | ||
return done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
it('Takes all results if no projection or empty object given', function (done) { | ||
var cursor = new Cursor(d, {}); | ||
cursor.sort({ age: 1 }); // For easier finding | ||
cursor.exec(function (err, docs) { | ||
assert.isNull(err); | ||
docs.length.should.equal(5); | ||
assert.deepEqual(docs[0], doc0); | ||
assert.deepEqual(docs[1], doc3); | ||
assert.deepEqual(docs[2], doc2); | ||
assert.deepEqual(docs[3], doc1); | ||
assert.deepEqual(docs[4], doc4); | ||
cursor.projection({}); | ||
cursor.exec(function (err, docs) { | ||
assert.isNull(err); | ||
docs.length.should.equal(5); | ||
assert.deepEqual(docs[0], doc0); | ||
assert.deepEqual(docs[1], doc3); | ||
assert.deepEqual(docs[2], doc2); | ||
assert.deepEqual(docs[3], doc1); | ||
assert.deepEqual(docs[4], doc4); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it('Can take only the expected fields', function (done) { | ||
var cursor = new Cursor(d, {}); | ||
cursor.sort({ age: 1 }); // For easier finding | ||
cursor.projection({ age: 1, name: 1 }); | ||
cursor.exec(function (err, docs) { | ||
assert.isNull(err); | ||
docs.length.should.equal(5); | ||
// Takes the _id by default | ||
assert.deepEqual(docs[0], { age: 5, name: 'Jo', _id: doc0._id }); | ||
assert.deepEqual(docs[1], { age: 23, name: 'LM', _id: doc3._id }); | ||
assert.deepEqual(docs[2], { age: 52, name: 'Grafitti', _id: doc2._id }); | ||
assert.deepEqual(docs[3], { age: 57, name: 'Louis', _id: doc1._id }); | ||
assert.deepEqual(docs[4], { age: 89, _id: doc4._id }); // No problems if one field to take doesn't exist | ||
cursor.projection({ age: 1, name: 1, _id: 0 }); | ||
cursor.exec(function (err, docs) { | ||
assert.isNull(err); | ||
docs.length.should.equal(5); | ||
assert.deepEqual(docs[0], { age: 5, name: 'Jo' }); | ||
assert.deepEqual(docs[1], { age: 23, name: 'LM' }); | ||
assert.deepEqual(docs[2], { age: 52, name: 'Grafitti' }); | ||
assert.deepEqual(docs[3], { age: 57, name: 'Louis' }); | ||
assert.deepEqual(docs[4], { age: 89 }); // No problems if one field to take doesn't exist | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it('Can omit only the expected fields', function (done) { | ||
var cursor = new Cursor(d, {}); | ||
cursor.sort({ age: 1 }); // For easier finding | ||
cursor.projection({ age: 0, name: 0 }); | ||
cursor.exec(function (err, docs) { | ||
assert.isNull(err); | ||
docs.length.should.equal(5); | ||
// Takes the _id by default | ||
assert.deepEqual(docs[0], { planet: 'B', _id: doc0._id }); | ||
assert.deepEqual(docs[1], { planet: 'S', _id: doc3._id }); | ||
assert.deepEqual(docs[2], { planet: 'C', _id: doc2._id }); | ||
assert.deepEqual(docs[3], { planet: 'R', _id: doc1._id }); | ||
assert.deepEqual(docs[4], { planet: 'Earth', _id: doc4._id }); | ||
cursor.projection({ age: 0, name: 0, _id: 0 }); | ||
cursor.exec(function (err, docs) { | ||
assert.isNull(err); | ||
docs.length.should.equal(5); | ||
assert.deepEqual(docs[0], { planet: 'B' }); | ||
assert.deepEqual(docs[1], { planet: 'S' }); | ||
assert.deepEqual(docs[2], { planet: 'C' }); | ||
assert.deepEqual(docs[3], { planet: 'R' }); | ||
assert.deepEqual(docs[4], { planet: 'Earth' }); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
it('Cannot use both modes except for _id', function (done) { | ||
var cursor = new Cursor(d, {}); | ||
cursor.sort({ age: 1 }); // For easier finding | ||
cursor.projection({ age: 1, name: 0 }); | ||
cursor.exec(function (err, docs) { | ||
assert.isNotNull(err); | ||
assert.isUndefined(docs); | ||
done(); | ||
}); | ||
}); | ||
}); // ==== End of 'Projections' ==== | ||
}); | ||
@@ -663,0 +786,0 @@ |
@@ -0,0 +0,0 @@ var should = require('chai').should() |
@@ -0,0 +0,0 @@ var should = require('chai').should() |
@@ -0,0 +0,0 @@ var Index = require('../lib/indexes') |
@@ -0,0 +0,0 @@ var model = require('../lib/model') |
@@ -0,0 +0,0 @@ var should = require('chai').should() |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
16893
637
702114
+ Addedbinary-search-tree@0.2.4(transitive)
- Removedbinary-search-tree@0.2.3(transitive)
Updatedbinary-search-tree@0.2.4