Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
eivindfjeldstad committed Feb 27, 2014
0 parents commit cbbfb99
Showing 6 changed files with 181 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
test:
@./node_modules/.bin/mocha \
--reporter spec

.PHONY: test
31 changes: 31 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

# mongo-query

Get object diff as a MongoDB update query.

Useful for reducing the size of your queries.
Uses (cloudup/mongo-eql)[https://github.com/cloudup/mongo-eql] to compare values and
and (cloudup/mongo-minify)[https://github.com/cloudup/mongo-minify] to optionally filter
out disallowed operations.

## Installation

$ npm install mongo-update

## Example

```js
var update = require('mongo-update');
var query = update({ a: 'hello' }, { b: 'world' });
// => { $set: { b: 'hello' }, $unset: { a: 1 }}
```

Or with a filter (see (cloudup/mongo-minify)[https://github.com/cloudup/mongo-minify] for more examples)
```js
var query = update({ a: 1, b: 2 }, { a: 2, b: 3 }, { a: 1 });
// => { $set: { a: 2 }}
```

## License

MIT
86 changes: 86 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
var minify = require('mongo-minify');
var is = require('component-type');
var eql = require('mongo-eql');

/**
* Get object diff as a MongoDB update query
*
* @param {Object} a
* @param {Object} b
* @param {Object} [filter]
* @return {Object}
* @api public
*/

module.exports = function (a, b, filter) {
var ret = {};
filter = filter || {};
diff(a, b, ret);
return minify(ret, filter);
}

/**
* Traverse both objects and put ops on the `query` object
*/

function diff (a, b, query, prefix) {
// find removed keys
for (var key in a) {
var path = join(key, prefix);
if (b[key] == null) unset(query, path);
}

// find changed keys
for (var key in b) {
var path = join(key, prefix);

// removed
if (b[key] == null) continue;

// no change
if (eql(a[key], b[key])) continue;

// new type
if (is(a[key]) != is(b[key])) {
set(query, path, b[key]);
continue;
}

// object
if (is(a[key]) == 'object') {
diff(a[key], b[key], query, path);
continue;
}

// default
set(query, path, b[key]);
}
}

/**
* $set `field` to `val`
*/

function set (query, field, val) {
query['$set'] = query['$set'] || {};
query['$set'][field] = val;
}

/**
* $unset `field`
*/

function unset (query, field) {
query['$unset'] = query['$unset'] || {};
query['$unset'][field] = 1;
};

/**
* Join `key` with `prefix` using dot-notation
*/

function join (key, prefix) {
return prefix
? prefix + '.' + key
: key;
}
22 changes: 22 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"name": "mongo-update",
"version": "0.0.1",
"description": "Get object diff as a MongoDB update query",
"main": "index.js",
"scripts": {
"test": "make test"
},
"license": "MIT",
"dependencies": {
"component-type": "~1.0.0",
"mongo-eql": "~0.1.0",
"mongo-minify": "~0.1.1"
},
"devDependencies": {
"mocha": "~1.17.1"
},
"repository": {
"type": "git",
"url": "https://github.com/eivindfjeldstad/mongo-update.git"
}
}
36 changes: 36 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
var assert = require('assert');
var diff = require('./');

describe('query()', function () {
it('should $set modified keys', function () {
var query = diff({ a: 1 }, { a: 2 });
assert(query.$set.a == 2);
assert(!('$unset' in query));
});

it('should $unset null-ish keys', function () {
var query = diff({ a: 1 }, { a: null });
assert(query.$unset.a == 1);
assert(!('$set' in query));
});

it('should work with nested keys', function () {
var query = diff({ a: { b: 1, c: 2 }}, { a: { b: 2 }});
assert(query.$set['a.b'] == 2);
assert(query.$unset['a.c'] == 1);
});

describe('when given a filter', function () {
it('should minify the query', function () {
var query = diff({ a: 1, b: 2 }, { a: 2, b: 3 }, { a: 1 });
assert(query.$set.a == 2);
assert(!('b' in query.$set));
});

it('should work with nested keys', function () {
var query = diff({ a: { b: 1, c: 2 }}, { a: { b: 2 }}, { 'a.b': 1 });
assert(query.$set['a.b'] == 2);
assert(!('$unset' in query));
});
});
})

0 comments on commit cbbfb99

Please sign in to comment.