Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

mquery

Package Overview
Dependencies
Maintainers
1
Versions
74
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mquery - npm Package Compare versions

Comparing version 0.0.1 to 0.1.0

lib/collection/collection.js

24

History.md
0.1.0 / 2013-05-06
==================
* findAndModify; return the query
* move mquery.proto.canMerge to mquery.canMerge
* overwrite option now works with non-empty objects
* use strict mode
* validate count options
* validate distinct options
* add aggregate to base collection methods
* clone merge arguments
* clone merged update arguments
* move subclass to mquery.prototype.toConstructor
* fixed; maxScan casing
* use regexp-clone
* added; geometry/intersects support
* support $and
* near: do not use "radius"
* callbacks always fire on next turn of loop
* defined collection interface
* remove time from tests
* clarify goals
* updated docs;
0.0.1 / 2012-12-15

@@ -3,0 +27,0 @@ ==================

1

lib/env.js

@@ -0,1 +1,2 @@

'use strict';

@@ -2,0 +3,0 @@ exports.isNode = 'undefined' != typeof process

499

lib/mquery.js

@@ -1,2 +0,2 @@

// mquery
'use strict';

@@ -11,14 +11,4 @@ /**

var utils = require('./utils')
var env = require('./env')
var debug = require('debug')('mquery');
// Goals
// =========
// provide interface 100% compatible with mongoose
// works standalone with the driver too
// works in mongo shell
// works in the browser
// works anywhere the collection api is implemented
// TODO specify requirements of a collection object
/**

@@ -33,4 +23,4 @@ * Query constructor used for building queries.

*
* @param {Object} criteria
* @param {Object} options
* @param {Object} [criteria]
* @param {Object} [options]
* @api public

@@ -43,15 +33,28 @@ */

this.op = null;
var proto = this.constructor.prototype;
this.op = proto.op || undefined;
this.options = {};
this._conditions = {};
this._fields = undefined;
this._update = undefined;
this._path = undefined;
this._distinct = undefined;
this.setOptions(proto.options);
// inherited default options if any
this.setOptions(this.constructor.prototype.options);
this._conditions = proto._conditions
? utils.clone(proto._conditions)
: {};
if (options)
this._fields = proto._fields
? utils.clone(proto._fields)
: undefined;
this._update = proto._update
? utils.clone(proto._update)
: undefined;
this._path = proto._path || undefined;
this._distinct = proto._distinct || undefined;
this._collection = proto._collection || undefined;
if (options) {
this.setOptions(options);
}

@@ -69,35 +72,49 @@ if (criteria) {

/**
* Create a custom subclassed mquery constructor.
* Converts this query to a constructor function with all arguments and options retained.
*
* For use with mongoose, one can use this for setting
* default the `safe` and `readPreference`. Each compiled
* mongoose model could then create this when constructed
* and use the subclassed query.
* ####Example
*
* model.Query = Query.custom({
* safe: this.schema.options.safe
* , readPreference: this.schema.options.read
* })
* // Create a query that will read documents with a "video" category from
* // `aCollection` on the primary node in the replica-set unless it is down,
* // in which case we'll read from a secondary node.
* var query = mquery({ category: 'video' })
* query.setOptions({ collection: aCollection, read: 'primaryPreferred' });
*
* model.find = function () {
* var query = new this.Query;
* ..
* }
* // create a constructor based off these settings
* var Video = query.toConstructor();
*
* // Video is now a subclass of mquery() and works the same way but with the
* // default query parameters and options set.
*
* // run a query with the previous settings but filter for movies with names
* // that start with "Life".
* Video().where({ name: /^Life/ }).exec(cb);
*
* @return {Query} new Query
* @api public
*/
Query.subclass = function (options) {
function CustomQuery () {
Query.prototype.toConstructor = function toConstructor () {
function CustomQuery (criteria, options) {
if (!(this instanceof CustomQuery))
return new CustomQuery(arguments[0], arguments[1]);
Query.apply(this, arguments);
return new CustomQuery(criteria, options);
Query.call(this, criteria, options);
}
// TODO make browser friendly
util.inherits(CustomQuery, Query);
utils.inherits(CustomQuery, Query);
// default options inheritance
CustomQuery.prototype.options = {};
CustomQuery.prototype.setOptions(options);
// set inherited defaults
var p = CustomQuery.prototype;
p.options = {};
p.setOptions(this.options);
p.op = this.op;
p._conditions = utils.clone(this._conditions);
p._fields = utils.clone(this._fields);
p._update = utils.clone(this._update);
p._path = this._path;
p._distict = this._distinct;
p._collection = this._collection;
return CustomQuery;

@@ -115,3 +132,3 @@ }

* - [skip](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bskip%28%29%7D%7D) *
* - [maxscan](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24maxScan) *
* - [maxScan](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24maxScan) *
* - [batchSize](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7BbatchSize%28%29%7D%7D) *

@@ -122,3 +139,2 @@ * - [comment](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%24comment) *

* - [slaveOk](http://docs.mongodb.org/manual/applications/replication/#read-preference) *
* - [lean](./api.html#query_Query-lean) *
* - [safe](http://www.mongodb.org/display/DOCS/getLastError+Command)

@@ -166,3 +182,3 @@ * - collection the collection to query against

Query.prototype.collection = function collection (coll) {
this._collection = coll;
this._collection = new Query.Collection(coll);
return this;

@@ -307,2 +323,22 @@ }

/**
* Specifies arguments for a `$and` condition.
*
* ####Example
*
* query.and([{ color: 'green' }, { status: 'ok' }])
*
* @see $and http://docs.mongodb.org/manual/reference/operator/and/
* @param {Array} array array of conditions
* @return {Query} this
* @api public
*/
Query.prototype.and = function and (array) {
var and = this._conditions.$and || (this._conditions.$and = []);
if (!Array.isArray(array)) array = [array];
and.push.apply(and, array);
return this;
}
/**
* Specifies a $gt query condition.

@@ -411,3 +447,3 @@ *

/**
* Specifies an $size query condition.
* Specifies a $size query condition.
*

@@ -620,2 +656,3 @@ * When called with one argument, the most recent path passed to `where()` is used.

* query.within().circle()
* query.within().geometry()
*

@@ -628,2 +665,3 @@ * query.where('loc').within({ center: [50,50], radius: 10, unique: true, spherical: true });

* query.where('loc').within([], []) // box
* query.where('loc').within({ type: 'LineString', coordinates: [...] }); // geometry
*

@@ -636,2 +674,7 @@ * @memberOf Query

Query.prototype.within = function within () {
// opinionated, must be used after where
this._ensurePath('within');
this._geoComparison = '$within';
if (0 === arguments.length) {

@@ -641,5 +684,2 @@ return this;

// opinionated, must be used after where
this._ensurePath('within');
if (2 === arguments.length) {

@@ -665,2 +705,5 @@ return this.box.apply(this, arguments);

if (area.type && area.coordinates)
return this.geometry(area);
throw new TypeError('Invalid argument');

@@ -804,6 +847,5 @@ }

* query.where('loc').near({ center: [10, 10] });
* query.where('loc').near({ center: [10, 10], radius: 5 });
* query.where('loc').near({ center: [10, 10], radius: 5, spherical: true });
* query.where('loc').near({ center: [10, 10], maxDistance: 5 });
* query.near('loc', { center: [10, 10], radius: 5 });
* query.where('loc').near({ center: [10, 10], maxDistance: 5, spherical: true });
* query.near('loc', { center: [10, 10], maxDistance: 5 });
*

@@ -842,7 +884,3 @@ * @param {String} [path]

// we use radius by default to keep terminology consistent with
// other geo methods. maxDistance is for mongodb compatibility
var radius = 'radius' in val
? val.radius
: 'maxDistance' in val
var radius = 'maxDistance' in val
? val.maxDistance

@@ -858,6 +896,102 @@ : null;

/**
* geoNear
* TODO
* Declares an intersects query for `geometry()`.
*
* ####Example
*
* query.where('path').intersects().geometry({
* type: 'LineString'
* , coordinates: [[180.0, 11.0], [180, 9.0]]
* })
*
* query.where('path').intersects({
* type: 'LineString'
* , coordinates: [[180.0, 11.0], [180, 9.0]]
* })
*
* @param {Object} [arg]
* @return {Query} this
* @api public
*/
Query.prototype.intersects = function intersects () {
// opinionated, must be used after where
this._ensurePath('intersects');
this._geoComparison = '$intersects';
if (0 === arguments.length) {
return this;
}
var area = arguments[0];
if (null != area && area.type && area.coordinates)
return this.geometry(area);
throw new TypeError('Invalid argument');
}
/**
* Specifies a `$geometry` condition
*
* ####Example
*
* var polyA = [[[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]]]
* query.where('loc').within().geometry({ type: 'Polygon', coordinates: polyA })
*
* // or
* var polyB = [[ 0, 0 ], [ 1, 1 ]]
* query.where('loc').within().geometry({ type: 'LineString', coordinates: polyB })
*
* // or
* var polyC = [ 0, 0 ]
* query.where('loc').within().geometry({ type: 'Point', coordinates: polyC })
*
* // or
* query.where('loc').intersects().geometry({ type: 'Point', coordinates: polyC })
*
* ####NOTE:
*
* `geometry()` **must** come after either `intersects()` or `within()`.
*
* The `object` argument must contain `type` and `coordinates` properties.
* - type {String}
* - coordinates {Array}
*
* The most recent path passed to `where()` is used.
*
* @param {Object} object Must contain a `type` property which is a String and a `coordinates` property which is an Array. See the examples.
* @return {Query} this
* @see http://docs.mongodb.org/manual/release-notes/2.4/#new-geospatial-indexes-with-geojson-and-improved-spherical-geometry
* @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing
* @see $geometry http://docs.mongodb.org/manual/reference/operator/geometry/
* @api public
*/
Query.prototype.geometry = function geometry () {
if (!('$within' == this._geoComparison ||
'$intersects' == this._geoComparison)) {
throw new Error('geometry() must come after either `within()` or `intersects()`');
}
var val, path;
if (1 === arguments.length) {
this._ensurePath('geometry');
path = this._path;
val = arguments[0];
} else {
throw new TypeError("Invalid argument");
}
if (!(val.type && Array.isArray(val.coordinates))) {
throw new TypeError('Invalid argument');
}
var conds = this._conditions[path] || (this._conditions[path] = {});
conds[this._geoComparison] = { $geometry: val };
return this;
}
// end spatial

@@ -881,2 +1015,6 @@

*
* ####Note
*
* Cannot be used with `distinct()`
*
* @param {Object|String} arg

@@ -892,2 +1030,4 @@ * @return {Query} this

this._validate('select');
var fields = this._fields || (this._fields = {});

@@ -944,2 +1084,4 @@ var type = typeof arg;

this._validate('slice');
var path, val;

@@ -983,2 +1125,6 @@

*
* ####Note
*
* Cannot be used with `distinct()`
*
* @param {Object|String} arg

@@ -992,3 +1138,4 @@ * @return {Query} this

var sort = this.options.sort || (this.options.sort = []);
this._validate('sort');
var type = typeof arg;

@@ -1004,3 +1151,3 @@

if (ascend === -1) field = field.substring(1);
push(sort, field, ascend);
push(this.options, field, ascend);
}

@@ -1015,3 +1162,3 @@

var field = keys[i];
push(sort, field, arg[field]);
push(this.options, field, arg[field]);
}

@@ -1029,3 +1176,3 @@

function push (arr, field, value) {
function push (opts, field, value) {
var val = String(value || 1).toLowerCase();

@@ -1036,2 +1183,3 @@ if (!/^(?:ascending|asc|descending|desc|1|-1)$/.test(val)) {

}
var arr = opts.sort || (opts.sort = []);
arr.push([field, value]);

@@ -1047,2 +1195,6 @@ }

*
* ####Note
*
* Cannot be used with `distinct()`
*
* @method limit

@@ -1061,2 +1213,6 @@ * @memberOf Query

*
* ####Note
*
* Cannot be used with `distinct()`
*
* @method skip

@@ -1069,9 +1225,13 @@ * @memberOf Query

/**
* Specifies the maxscan option.
* Specifies the maxScan option.
*
* ####Example
*
* query.maxscan(100)
* query.maxScan(100)
*
* @method maxscan
* ####Note
*
* Cannot be used with `distinct()`
*
* @method maxScan
* @memberOf Query

@@ -1089,2 +1249,6 @@ * @param {Number} val

*
* ####Note
*
* Cannot be used with `distinct()`
*
* @method batchSize

@@ -1103,2 +1267,6 @@ * @memberOf Query

*
* ####Note
*
* Cannot be used with `distinct()`
*
* @method comment

@@ -1112,3 +1280,3 @@ * @memberOf Query

/*!
* limit, skip, maxscan, batchSize, comment
* limit, skip, maxScan, batchSize, comment
*

@@ -1120,4 +1288,5 @@ * Sets these associated options.

;['limit', 'skip', 'maxscan', 'batchSize', 'comment'].forEach(function (method) {
;['limit', 'skip', 'maxScan', 'batchSize', 'comment'].forEach(function (method) {
Query.prototype[method] = function (v) {
this._validate(method);
this.options[method] = v;

@@ -1137,2 +1306,6 @@ return this;

*
* ####Note
*
* Cannot be used with `distinct()`
*
* @see mongodb http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-%7B%7Bsnapshot%28%29%7D%7D

@@ -1144,5 +1317,8 @@ * @return {Query} this

Query.prototype.snapshot = function () {
this._validate('snapshot');
this.options.snapshot = arguments.length
? !! arguments[0]
: true
return this;

@@ -1158,2 +1334,6 @@ }

*
* ####Note
*
* Cannot be used with `distinct()`
*
* @param {Object} val a hint object

@@ -1168,2 +1348,4 @@ * @return {Query} this

this._validate('hint');
var arg = arguments[0];

@@ -1185,3 +1367,3 @@ if (utils.isObject(arg)) {

/**
* Sets the slaveOk option.
* Sets the slaveOk option. _Deprecated_ in MongoDB 2.2 in favor of read preferences.
*

@@ -1207,10 +1389,2 @@ * ####Example:

// TODO write concern
// Query.prototype.replicate = function (n) {
// this.options.w = Number(n) || 1; // ??
// // TODO be backwards compatible by setting safe
// this.options.safe = { w: this.options.w };
// return this;
// }
/**

@@ -1279,2 +1453,6 @@ * Sets the readPreference option for the query.

*
* ####Note
*
* Cannot be used with `distinct()`
*
* @param {Boolean} v defaults to true

@@ -1286,5 +1464,8 @@ * @see mongodb http://www.mongodb.org/display/DOCS/Tailable+Cursors

Query.prototype.tailable = function () {
this._validate('tailable');
this.options.tailable = arguments.length
? !! arguments[0]
: true;
return this;

@@ -1296,3 +1477,3 @@ }

*
* When a Query is passed, Query conditions, field selection and options are merged.
* When a Query is passed, conditions, field selection and options are merged.
*

@@ -1307,6 +1488,8 @@ * @param {Query|Object} source

if (!(source instanceof Query || utils.isObject(source)))
if (!Query.canMerge(source))
throw new TypeError('Invalid argument. Expected instanceof mquery or plain object');
if (source instanceof Query) {
// if source has a feature, apply it to ourselves
if (source._conditions) {

@@ -1326,8 +1509,9 @@ utils.merge(this._conditions, source._conditions);

if (source._distinct && !this._distinct) {
this._distinct = source._distinct;
if (source._update) {
this._update || (this._update = {});
utils.mergeClone(this._update, source._update);
}
if (source._update && !this._update) {
this._update = source._update;
if (source._distinct) {
this._distinct = source._distinct;
}

@@ -1351,3 +1535,5 @@

*
* query.find({ name: 'Los Pollos Hermanos' }).find(callback)
* query.find()
* query.find(callback)
* query.find({ name: 'Burning Lights' }, callback)
*

@@ -1366,3 +1552,3 @@ * @param {Object} [criteria] mongodb selector

criteria = undefined;
} else if (this.canMerge(criteria)) {
} else if (Query.canMerge(criteria)) {
this.merge(criteria);

@@ -1373,4 +1559,2 @@ }

this._ensureMethod('find');
var self = this

@@ -1384,3 +1568,3 @@ , conds = this._conditions

this._collection.find(conds, options, callback);
this._collection.find(conds, options, utils.tick(callback));
return this;

@@ -1396,7 +1580,7 @@ }

*
* query.findOne().where('name', /^Los/);
* query.findOne().where('name', /^Burning/);
*
* query.findOne({ name: /^Los/ })
* query.findOne({ name: /^Burning/ })
*
* query.findOne({ name: /^Los/ }, callback); // executes
* query.findOne({ name: /^Burning/ }, callback); // executes
*

@@ -1423,3 +1607,3 @@ * query.findOne(function (err, doc) {

criteria = undefined;
} else if (this.canMerge(criteria)) {
} else if (Query.canMerge(criteria)) {
this.merge(criteria);

@@ -1430,4 +1614,2 @@ }

this._ensureMethod('findOne');
var self = this

@@ -1472,2 +1654,3 @@ , conds = this._conditions

this.op = 'count';
this._validate();

@@ -1477,3 +1660,3 @@ if ('function' === typeof criteria) {

criteria = undefined;
} else if (this.canMerge(criteria)) {
} else if (Query.canMerge(criteria)) {
this.merge(criteria);

@@ -1484,4 +1667,2 @@ }

this._ensureMethod('count');
var conds = this._conditions

@@ -1519,2 +1700,3 @@ , options = this._optionsForExec()

this.op = 'distinct';
this._validate();

@@ -1550,16 +1732,17 @@ if (!callback) {

if ('string' == typeof field)
if ('string' == typeof field) {
this._distinct = field;
}
if (this.canMerge(criteria)) {
if (Query.canMerge(criteria)) {
this.merge(criteria);
}
if (!callback)
if (!callback) {
return this;
}
this._ensureMethod('distinct');
if (!this._distinct)
if (!this._distinct) {
throw new Error('No value for `distinct` has been declared');
}

@@ -1688,3 +1871,3 @@ var conds = this._conditions

if (this.canMerge(criteria)) {
if (Query.canMerge(criteria)) {
this.merge(criteria);

@@ -1707,7 +1890,5 @@ }

this._ensureMethod('update');
if (!this._update ||
!this.options.overwrite && 0 === utils.keys(this._update).length) {
callback && process.nextTick(callback.bind(null, null, 0));
callback && utils.soon(callback.bind(null, null, 0));
return this;

@@ -1768,3 +1949,3 @@ }

criteria = undefined;
} else if (this.canMerge(criteria)) {
} else if (Query.canMerge(criteria)) {
this.merge(criteria);

@@ -1779,4 +1960,2 @@ } else if (true === criteria) {

this._ensureMethod('remove');
var options = this._optionsForExec()

@@ -1796,3 +1975,3 @@ if (!callback) options.safe = false;

*
* Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any) to the callback. The query executes immediately if `callback` is passed else a Query object is returned.
* Finds a matching document, updates it according to the `update` arg, passing any `options`, and returns the found document (if any) to the callback. The query executes immediately if `callback` is passed.
*

@@ -1853,3 +2032,3 @@ * ####Available options

if (this.canMerge(criteria)) {
if (Query.canMerge(criteria)) {
this.merge(criteria);

@@ -1872,3 +2051,3 @@ }

*
* Finds a matching document, removes it, passing the found document (if any) to the callback. Executes immediately if `callback` is passed else a Query object is returned.
* Finds a matching document, removes it, passing the found document (if any) to the callback. Executes immediately if `callback` is passed.
*

@@ -1908,3 +2087,3 @@ * ####Available options

// apply conditions
if (this.canMerge(conditions)) {
if (Query.canMerge(conditions)) {
this.merge(conditions);

@@ -1930,4 +2109,2 @@ }

Query.prototype._findAndModify = function (type, callback) {
this._ensureMethod('findAndModify');
assert.equal('function', typeof callback);

@@ -1953,4 +2130,3 @@

} else {
this.findOne(callback);
return;
return this.findOne(callback);
}

@@ -1971,2 +2147,4 @@ }

.findAndModify(conds, doc, opts, utils.tick(callback));
return this;
}

@@ -2011,13 +2189,2 @@

/**
* Determines if `conds` can be merged using `this.merge()`
*
* @param {Object} conds
* @return {Boolean}
*/
Query.prototype.canMerge = function (conds) {
return conds instanceof Query || utils.isObject(conds);
}
/**
* Merges `doc` with the current update object.

@@ -2032,6 +2199,6 @@ *

if (doc._update) {
utils.merge(this._update, doc._update);
utils.mergeClone(this._update, doc._update);
}
} else {
utils.merge(this._update, doc);
utils.mergeClone(this._update, doc);
}

@@ -2049,6 +2216,2 @@ }

var options = utils.clone(this.options, { retainKeyOrder: true });
// default options like `safe` and `readPreference` are not
// set by using Query.custom({ safe: defaultVal, readPreference: defaultVal})
return options;

@@ -2083,2 +2246,8 @@ }

var op = ops[i];
if (this.options.overwrite) {
ret[op] = this._update[op];
continue;
}
if ('$' !== op[0]) {

@@ -2122,17 +2291,45 @@ // fix up $set sugar

/*!
* Permissions
*/
Query.permissions = require('./permissions');
Query._isPermitted = function (a, b) {
var denied = Query.permissions[b];
if (!denied) return true;
return true !== denied[a];
}
Query.prototype._validate = function (action) {
var fail;
var validator;
if (undefined === action) {
validator = Query.permissions[this.op];
if ('function' != typeof validator) return true;
fail = validator(this);
} else if (!Query._isPermitted(action, this.op)) {
fail = action;
}
if (fail) {
throw new Error(fail + ' cannot be used with ' + this.op);
}
}
/**
* Ensures `method` exists on the `_collection`
* Determines if `conds` can be merged using `mquery().merge()`
*
* @api private
* @param {Object} conds
* @return {Boolean}
*/
Query.prototype._ensureMethod = function (method) {
if (!this._collection[method]) {
throw new Error(method + ' method not implemented by collection interface')
}
Query.canMerge = function (conds) {
return conds instanceof Query || utils.isObject(conds);
}
// Stream interface is not a general use case. Implement at higher level (in
// nodejs collection)
/*!

@@ -2142,13 +2339,9 @@ * Exports.

Query.env = env;
Query.utils = utils;
Query.env = require('./env')
Query.Collection = require('./collection');
Query.BaseCollection = require('./collection/collection');
module.exports = exports = Query;
// allow collection abstractions, do not tightly couple to node driver
//
// TODO
// merge utils into this file for browser/mongo shell version
// merge required libs (sliced, utils) ??
//
// TODO
// test utils

@@ -0,1 +1,2 @@

'use strict';

@@ -9,2 +10,3 @@ /*!

, ObjectId = mongodb.ObjectID
, RegExpClone = require('regexp-clone')

@@ -37,4 +39,5 @@ /**

if ('RegExp' === obj.constructor.name)
return new RegExp(obj.source);
if ('RegExp' === obj.constructor.name) {
return RegExpClone(obj);
}

@@ -118,11 +121,11 @@ if (obj instanceof ObjectId)

return function () {
try {
callback.apply(this, arguments);
} catch (err) {
// only nextTick on err to get out of
// the event loop and avoid state corruption.
process.nextTick(function () {
throw err;
});
}
// callbacks should always be fired on the next
// turn of the event loop. A side benefit is
// errors thrown from executing the callback
// will not cause drivers state to be corrupted
// which has historically been a problem.
var args = arguments;
soon(function(){
callback.apply(this, args);
});
}

@@ -159,2 +162,29 @@ }

/**
* Same as merge but clones the assigned values.
*
* @param {Object} to
* @param {Object} from
* @api private
*/
var mergeClone = exports.mergeClone = function mergeClone (to, from) {
var keys = Object.keys(from)
, i = keys.length
, key
while (i--) {
key = keys[i];
if ('undefined' === typeof to[key]) {
to[key] = clone(from[key]);
} else {
if (exports.isObject(from[key])) {
mergeClone(to[key], from[key]);
} else {
to[key] = clone(from[key]);
}
}
}
}
/**
* Read pref helper (mongo 2.2 drivers support this)

@@ -245,1 +275,40 @@ *

}
/**
* Basic Object.create polyfill.
* Only one argument is supported.
*
* Based on https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create
*/
exports.create = 'function' == typeof Object.create
? Object.create
: create;
function create (proto) {
if (arguments.length > 1) {
throw new Error("Adding properties is not supported")
}
function F () {}
F.prototype = proto;
return new F;
}
/**
* inheritance
*/
exports.inherits = function (ctor, superCtor) {
ctor.prototype = exports.create(superCtor.prototype);
ctor.prototype.constructor = ctor;
}
/**
* nextTick helper
* compat with node 0.10 which behaves differently than previous versions
*/
var soon = exports.soon = 'function' == typeof setImmediate
? setImmediate
: process.nextTick;
{
"name": "mquery",
"version": "0.0.1",
"version": "0.1.0",
"description": "Expressive query building for MongoDB",

@@ -19,10 +19,11 @@ "main": "index.js",

"sliced": "0.0.3",
"debug": "0.7.0"
"debug": "0.7.0",
"regexp-clone": "0.0.1"
},
"devDependencies": {
"mocha": "1.5.0",
"mongodb": "1.1.8"
"mocha": "1.9.x",
"mongodb": "1.3.0"
},
"bugs": {
"url":"https://github.com/learnboost/mquery/issues/new"
"url":"https://github.com/aheckmann/mquery/issues/new"
},

@@ -32,3 +33,3 @@ "author": "Aaron Heckmann <aaron.heckmann+github@gmail.com>",

"keywords": ["mongodb","query","builder"],
"homepage": "https://github.com/learnboost/mquery/"
"homepage": "https://github.com/aheckmann/mquery/"
}
#mquery
===========
Expressive MongoDB query builder.
Expressive MongoDB query builder
_work in progress_
##Features
## Installation
- fluent query builder api
- custom base query support
- MongoDB 2.4 geoJSON support
- method + option combinations validation
- node.js driver compatibility
- environment detection
- [debug](https://github.com/visionmedia/debug) support
- separated collection implementations for maximum flexibility
via npm:
##Use
$ npm install mquery
```js
require('mongodb').connect(uri, function (err, db) {
if (err) return handleError(err);
Goals:
// get a collection
var collection = db.collection('artists');
- flexible
- consistant API
- customizable
- browser compatibile
- compatibile with any driver (node-mongodb-native, mongo shell, etc)
// pass it to the constructor
mquery(collection).find({..}, callback);
// or pass it to the collection method
mquery().find({..}).collection(collection).exec(callback)
// or better yet, create a custom query constructor that has it always set
var Artist = mquery(collection).toConstructor();
Artist().find(..).where(..).exec(callback)
})
```
`mquery` requires a collection object to work with. In the example above we just pass the collection object created using the official [MongoDB driver](https://github.com/mongodb/node-mongodb-native).
##Fluent API
###find()
Declares this query a _find_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed.
```js
mquery().find()
mquery().find(match)
mquery().find(callback)
mquery().find(match, function (err, docs) {
assert(Array.isArray(docs));
})
```
###findOne()
Declares this query a _findOne_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed.
```js
mquery().findOne()
mquery().findOne(match)
mquery().findOne(callback)
mquery().findOne(match, function (err, doc) {
if (doc) {
// the document may not be found
console.log(doc);
}
})
```
###count()
Declares this query a _count_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed.
```js
mquery().count()
mquery().count(match)
mquery().count(callback)
mquery().count(match, function (err, number){
console.log('we found %d matching documents', number);
})
```
###remove()
Declares this query a _remove_ query. Optionally pass a match clause and / or callback. If a callback is passed the query is executed.
```js
mquery().remove()
mquery().remove(match)
mquery().remove(callback)
mquery().remove(match, function (err){})
```
###update()
Declares this query an _update_ query. Optionally pass an update document, match clause, options or callback. If a callback is passed, the query is executed. To force execution without passing a callback, run `update(true)`.
```js
mquery().update()
mquery().update(match, updateDocument)
mquery().update(match, updateDocument, options)
// the following all execute the command
mquery().update(callback)
mquery().update({$set: updateDocument, callback)
mquery().update(match, updateDocument, callback)
mquery().update(match, updateDocument, options, function (err, result){})
mquery().update(true) // executes (unsafe write)
```
#####the update document
All paths passed that are not `$atomic` operations will become `$set` ops. For example:
```js
mquery(collection).where({ _id: id }).update({ title: 'words' }, callback)
```
becomes
```js
collection.update({ _id: id }, { $set: { title: 'words' }}, callback)
```
This behavior can be overridden using the `overwrite` option (see below).
#####options
Options are passed to the `setOptions()` method.
- overwrite
Passing an empty object `{ }` as the update document will result in a no-op unless the `overwrite` option is passed. Without the `overwrite` option, the update operation will be ignored and the callback executed without sending the command to MongoDB to prevent accidently overwritting documents in the collection.
```js
var q = mquery(collection).where({ _id: id }).setOptions({ overwrite: true });
q.update({ }, callback); // overwrite with an empty doc
```
The `overwrite` option isn't just for empty objects, it also provides a means to override the default `$set` conversion and send the update document as is.
```js
// create a base query
var base = mquery({ _id: 108 }).collection(collection).toConstructor();
base().findOne(function (err, doc) {
console.log(doc); // { _id: 108, name: 'cajon' })
base().setOptions({ overwrite: true }).update({ changed: true }, function (err) {
base.findOne(function (err, doc) {
console.log(doc); // { _id: 108, changed: true }) - the doc was overwritten
});
});
})
```
- multi
Updates only modify a single document by default. To update multiple documents, set the `multi` option to `true`.
```js
mquery()
.collection(coll)
.update({ name: /^match/ }, { $addToSet: { arr: 4 }}, { multi: true }, callback)
// another way of doing it
mquery({ name: /^match/ })
.collection(coll)
.setOptions({ multi: true })
.update({ $addToSet: { arr: 4 }}, callback)
// update multiple documents with an empty doc
var q = mquery(collection).where({ name: /^match/ });
q.setOptions({ multi: true, overwrite: true })
q.update({ });
q.update(function (err, result) {
console.log(arguments);
});
```
###findOneAndUpdate()
Declares this query a _findAndModify_ with update query. Optionally pass a match clause, update document, options, or callback. If a callback is passed, the query is executed.
When executed, the first matching document (if found) is modified according to the update document and passed back to the callback.
#####options
Options are passed to the `setOptions()` method.
- `new`: boolean - true to return the modified document rather than the original. defaults to true
- `upsert`: boolean - creates the object if it doesn't exist. defaults to false
- `sort`: if multiple docs are found by the match condition, sets the sort order to choose which doc to update
```js
query.findOneAndUpdate()
query.findOneAndUpdate(updateDocument)
query.findOneAndUpdate(match, updateDocument)
query.findOneAndUpdate(match, updateDocument, options)
// the following all execute the command
query.findOneAndUpdate(callback)
query.findOneAndUpdate(updateDocument, callback)
query.findOneAndUpdate(match, updateDocument, callback)
query.findOneAndUpdate(match, updateDocument, options, function (err, doc) {
if (doc) {
// the document may not be found
console.log(doc);
}
})
```
###findOneAndRemove()
Declares this query a _findAndModify_ with remove query. Optionally pass a match clause, options, or callback. If a callback is passed, the query is executed.
When executed, the first matching document (if found) is modified according to the update document, removed from the collection and passed to the callback.
#####options
Options are passed to the `setOptions()` method.
- `sort`: if multiple docs are found by the condition, sets the sort order to choose which doc to modify and remove
```js
A.where().findOneAndRemove()
A.where().findOneAndRemove(match)
A.where().findOneAndRemove(match, options)
// the following all execute the command
A.where().findOneAndRemove(callback)
A.where().findOneAndRemove(match, callback)
A.where().findOneAndRemove(match, options, function (err, doc) {
if (doc) {
// the document may not be found
console.log(doc);
}
})
```
###distinct()
Declares this query a _distinct_ query. Optionally pass the distinct field, a match clause or callback. If a callback is passed the query is executed.
```js
mquery().distinct()
mquery().distinct(match)
mquery().distinct(match, field)
mquery().distinct(field)
// the following all execute the command
mquery().distinct(callback)
mquery().distinct(field, callback)
mquery().distinct(match, callback)
mquery().distinct(match, field, function (err, result) {
console.log(result);
})
```
###exec()
Executes the query.
```js
mquery().findOne().where('route').intersects(polygon).exec(function (err, docs){})
```
-------------
###all()
Specifies an `$all` query condition
```js
mquery().where('permission').all(['read', 'write'])
```
[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/all/)
###and()
Specifies arguments for an `$and` condition
```js
mquery().and([{ color: 'green' }, { status: 'ok' }])
```
[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/and/)
###box()
Specifies a `$box` condition
```js
var lowerLeft = [40.73083, -73.99756]
var upperRight= [40.741404, -73.988135]
mquery().where('location').within().box(lowerLeft, upperRight)
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/box/)
###circle()
Specifies a `$center` or `$centerSphere` condition.
```js
var area = { center: [50, 50], radius: 10, unique: true }
query.where('loc').within().circle(area)
query.center('loc', area);
// for spherical calculations
var area = { center: [50, 50], radius: 10, unique: true, spherical: true }
query.where('loc').within().circle(area)
query.center('loc', area);
```
- [MongoDB Documentation - center](http://docs.mongodb.org/manual/reference/operator/center/)
- [MongoDB Documentation - centerSphere](http://docs.mongodb.org/manual/reference/operator/centerSphere/)
###elemMatch()
Specifies an `$elemMatch` condition
```js
query.where('comment').elemMatch({ author: 'autobot', votes: {$gte: 5}})
query.elemMatch('comment', function (elem) {
elem.where('author').equals('autobot');
elem.where('votes').gte(5);
})
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/elemMatch/)
###equals()
Specifies the complementary comparison value for the path specified with `where()`.
```js
mquery().where('age').equals(49);
// is the same as
mquery().where({ 'age': 49 });
```
###exists()
Specifies an `$exists` condition
```js
// { name: { $exists: true }}
mquery().where('name').exists()
mquery().where('name').exists(true)
mquery().exists('name')
// { name: { $exists: false }}
mquery().where('name').exists(false);
mquery().exists('name', false);
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/exists/)
###geometry()
Specifies a `$geometry` condition
```js
var polyA = [[[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]]]
query.where('loc').within().geometry({ type: 'Polygon', coordinates: polyA })
// or
var polyB = [[ 0, 0 ], [ 1, 1 ]]
query.where('loc').within().geometry({ type: 'LineString', coordinates: polyB })
// or
var polyC = [ 0, 0 ]
query.where('loc').within().geometry({ type: 'Point', coordinates: polyC })
// or
query.where('loc').intersects().geometry({ type: 'Point', coordinates: polyC })
```
`geometry()` **must** come after either `intersects()` or `within()`.
The `object` argument must contain `type` and `coordinates` properties.
- type `String`
- coordinates `Array`
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/geometry/)
###gt()
Specifies a `$gt` query condition.
```js
mquery().where('clicks').gt(999)
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/gt/)
###gte()
Specifies a `$gte` query condition.
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/gte/)
```js
mquery().where('clicks').gte(1000)
```
###in()
Specifies an `$in` query condition.
```js
mquery().where('author_id').in([3, 48901, 761])
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/in/)
###intersects()
Declares an `$geoIntersects` query for `geometry()`.
```js
query.where('path').intersects().geometry({
type: 'LineString'
, coordinates: [[180.0, 11.0], [180, 9.0]]
})
// geometry arguments are supported
query.where('path').intersects({
type: 'LineString'
, coordinates: [[180.0, 11.0], [180, 9.0]]
})
```
**Must** be used after `where()`.
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/geoIntersects/)
###lt()
Specifies a `$lt` query condition.
```js
mquery().where('clicks').lt(50)
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/lt/)
###lte()
Specifies a `$lte` query condition.
```js
mquery().where('clicks').lte(49)
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/lte/)
###maxDistance()
Specifies a `$maxDistance` query condition.
```js
mquery().where('location').near({ center: [139, 74.3] }).maxDistance(5)
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/maxDistance/)
###mod()
Specifies a `$mod` condition
```js
mquery().where('count').mod(2, 0)
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/mod/)
###ne()
Specifies a `$ne` query condition.
```js
mquery().where('status').ne('ok')
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/ne/)
###nin()
Specifies an `$nin` query condition.
```js
mquery().where('author_id').nin([3, 48901, 761])
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/nin/)
###nor()
Specifies arguments for an `$nor` condition.
```js
mquery().nor([{ color: 'green' }, { status: 'ok' }])
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/nor/)
###or()
Specifies arguments for an `$or` condition.
```js
mquery().or([{ color: 'red' }, { status: 'emergency' }])
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/or/)
###polygon()
Specifies a `$polygon` condition
```js
mquery().where('loc').within().polygon([10,20], [13, 25], [7,15])
mquery().polygon('loc', [10,20], [13, 25], [7,15])
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/polygon/)
###regex()
Specifies a `$regex` query condition.
```js
mquery().where('name').regex(/^sixstepsrecords/)
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/regex/)
###select()
Specifies which document fields to include or exclude
```js
// 1 means include, 0 means exclude
mquery().select({ name: 1, address: 1, _id: 0 })
// or
mquery().select('name address -_id')
```
#####String syntax
When passing a string, prefixing a path with `-` will flag that path as excluded. When a path does not have the `-` prefix, it is included.
```js
// include a and b, exclude c
query.select('a b -c');
// or you may use object notation, useful when
// you have keys already prefixed with a "-"
query.select({a: 1, b: 1, c: 0});
```
_Cannot be used with `distinct()`._
###size()
Specifies a `$size` query condition.
```js
mquery().where('someArray').size(6)
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/size/)
###slice()
Specifies a `$slice` projection for a `path`
```js
mquery().where('comments').slice(5)
mquery().where('comments').slice(-5)
mquery().where('comments').slice([-10, 5])
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/projection/slice/)
###within()
Sets a `$within` argument for geo-spatial queries
```js
mquery().within().box()
mquery().within().circle()
mquery().within().geometry()
mquery().where('loc').within({ center: [50,50], radius: 10, unique: true, spherical: true });
mquery().where('loc').within({ box: [[40.73, -73.9], [40.7, -73.988]] });
mquery().where('loc').within({ polygon: [[],[],[],[]] });
mquery().where('loc').within([], [], []) // polygon
mquery().where('loc').within([], []) // box
mquery().where('loc').within({ type: 'LineString', coordinates: [...] }); // geometry
```
[MongoDB Documentation](http://docs.mongodb.org/manual/reference/operator/geoWithin/)
###where()
Specifies a `path` for use with chaining
```js
// instead of writing:
mquery().find({age: {$gte: 21, $lte: 65}});
// we can instead write:
mquery().where('age').gte(21).lte(65);
// passing query conditions is permitted too
mquery().find().where({ name: 'vonderful' })
// chaining
mquery()
.where('age').gte(21).lte(65)
.where({ 'name': /^vonderful/i })
.where('friends').slice(10)
.exec(callback)
```
###$where()
Specifies a `$where` condition.
Use `$where` when you need to select documents using a JavaScript expression.
```js
query.$where('this.comments.length > 10 || this.name.length > 5').exec(callback)
query.$where(function () {
return this.comments.length > 10 || this.name.length > 5;
})
```
Only use `$where` when you have a condition that cannot be met using other MongoDB operators like `$lt`. Be sure to read about all of [its caveats](http://docs.mongodb.org/manual/reference/operator/where/) before using.
-----------
###batchSize()
Specifies the batchSize option.
```js
query.batchSize(100)
```
_Cannot be used with `distinct()`._
[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.batchSize/)
###comment()
Specifies the comment option.
```js
query.comment('login query');
```
_Cannot be used with `distinct()`._
[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/)
###hint()
Sets query hints.
```js
mquery().hint({ indexA: 1, indexB: -1 })
```
_Cannot be used with `distinct()`._
[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/hint/)
###limit()
Specifies the limit option.
```js
query.limit(20)
```
_Cannot be used with `distinct()`._
[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.limit/)
###maxScan()
Specifies the maxScan option.
```js
query.maxScan(100)
```
_Cannot be used with `distinct()`._
[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/maxScan/)
###skip()
Specifies the skip option.
```js
query.skip(100).limit(20)
```
_Cannot be used with `distinct()`._
[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.skip/)
###sort()
Sets the query sort order.
If an object is passed, key values allowed are `asc`, `desc`, `ascending`, `descending`, `1`, and `-1`.
If a string is passed, it must be a space delimited list of path names. The sort order of each path is ascending unless the path name is prefixed with `-` which will be treated as descending.
```js
// these are equivalent
query.sort({ field: 'asc', test: -1 });
query.sort('field -test');
```
_Cannot be used with `distinct()`._
[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/cursor.sort/)
###read()
Sets the readPreference option for the query.
```js
mquery().read('primary')
mquery().read('p') // same as primary
mquery().read('primaryPreferred')
mquery().read('pp') // same as primaryPreferred
mquery().read('secondary')
mquery().read('s') // same as secondary
mquery().read('secondaryPreferred')
mquery().read('sp') // same as secondaryPreferred
mquery().read('nearest')
mquery().read('n') // same as nearest
// specifying tags
mquery().read('s', [{ dc:'sf', s: 1 },{ dc:'ma', s: 2 }])
```
#####Preferences:
- `primary` - (default) Read from primary only. Operations will produce an error if primary is unavailable. Cannot be combined with tags.
- `secondary` - Read from secondary if available, otherwise error.
- `primaryPreferred` - Read from primary if available, otherwise a secondary.
- `secondaryPreferred` - Read from a secondary if available, otherwise read from the primary.
- `nearest` - All operations read from among the nearest candidates, but unlike other modes, this option will include both the primary and all secondaries in the random selection.
Aliases
- `p` primary
- `pp` primaryPreferred
- `s` secondary
- `sp` secondaryPreferred
- `n` nearest
Read more about how to use read preferrences [here](http://docs.mongodb.org/manual/applications/replication/#read-preference) and [here](http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences).
###slaveOk()
Sets the slaveOk option. `true` allows reading from secondaries.
**deprecated** use [read()](#read) preferences instead if on mongodb >= 2.2
```js
query.slaveOk() // true
query.slaveOk(true)
query.slaveOk(false)
```
[MongoDB documentation](http://docs.mongodb.org/manual/reference/method/rs.slaveOk/)
###snapshot()
Specifies this query as a snapshot query.
```js
mquery().snapshot() // true
mquery().snapshot(true)
mquery().snapshot(false)
```
_Cannot be used with `distinct()`._
[MongoDB documentation](http://docs.mongodb.org/manual/reference/operator/snapshot/)
###tailable()
Sets tailable option.
```js
mquery().tailable() <== true
mquery().tailable(true)
mquery().tailable(false)
```
_Cannot be used with `distinct()`._
[MongoDB Documentation](http://docs.mongodb.org/manual/tutorial/create-tailable-cursor/)
##Helpers
###collection()
Sets the querys collection.
```js
mquery().collection(aCollection)
```
###merge(object)
Merges other mquery or match condition objects into this one. When an muery instance is passed, its match conditions, field selection and options are merged.
```js
var drum = mquery({ type: 'drum' }).collection(instruments);
var redDrum = mqery({ color: 'red' }).merge(drum);
redDrum.count(function (err, n) {
console.log('there are %d red drums', n);
})
```
Internally uses `Query.canMerge` to determine validity.
###setOptions(options)
Sets query options.
```js
mquery().setOptions({ collection: coll, limit: 20 })
```
#####options
- [tailable](#tailable) *
- [sort](#sort) *
- [limit](#limit) *
- [skip](#skip) *
- [maxScan](#maxScan) *
- [batchSize](#batchSize) *
- [comment](#comment) *
- [snapshot](#snapshot) *
- [hint](#hint) *
- [slaveOk](#slaveOk) *
- [safe](http://docs.mongodb.org/manual/reference/write-concern/): Boolean - passed through to the collection. Setting to `true` is equivalent to `{ w: 1 }`
- [collection](#collection): the collection to query against
_* denotes a query helper method is also available_
###Query.canMerge(conditions)
Determines if `conditions` can be merged using `mquery().merge()`.
```js
var query = mquery({ type: 'drum' });
var okToMerge = mquery.canMerge(anObject)
if (okToMerge) {
query.merge(anObject);
}
```
##Custom Base Queries
Often times we want custom base queries that encapsulate predefined criteria. With `mquery` this is easy. First create the query you want to reuse and call its `toConstructor()` method which returns a new subclass of `mquery` that retains all options and criteria of the original.
```js
var greatMovies = mquery(movieCollection).where('rating').gte(4.5).toConstructor();
// use it!
greatMovies().count(function (err, n) {
console.log('There are %d great movies', n);
});
greatMovies().where({ name: /^Life/ }).select('name').find(function (err, docs) {
console.log(docs);
});
```
##Validation
Method and options combinations are checked for validity at runtime to prevent creation of invalid query constructs. For example, a `distinct` query does not support specifying options like `hint` or field selection. In this case an error will be thrown so you can catch these mistakes in development.
##Debug support
Debug mode is provided through the use of the [debug](https://github.com/visionmedia/debug) module. To enable:
DEBUG=mquery node yourprogram.js
Read the debug module documentation for more details.
##Future goals
- mongo shell compatibility
- browser compatibility
- mongoose compatibility
## Installation
$ npm install mquery
## License
[MIT](https://github.com/aheckmann/mquery/blob/master/LICENSE)

@@ -14,25 +14,4 @@

db = db_;
var collection = db.collection('stuff');
// normalize the driver find api
var find = collection.find;
collection.find = function () {
// sidestep need to call toArray
var args = slice(arguments);
if ('function' == typeof args[args.length-1]) {
var cb = args.pop();
return find.apply(collection, args).toArray(utils.tick(cb));
} else {
return find.apply(collection, args);
}
}
// normalize the driver findAndModify api
var findAndModify = collection.findAndModify;
collection.findAndModify = function (conds, doc, opts, cb) {
// node-mongodb-native requires a sort arg
var sort = opts.sort || [];
return findAndModify.call(collection, conds, sort, doc, opts, cb);
}
collection.opts.safe = true;

@@ -39,0 +18,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc