Skip to content

Commit d585b1f

Browse files
author
Oliver Rumbelow
committed
Merge pull request #10 from holidayextras/db-filter
Handle all filtering at the database layer
2 parents f20f519 + 99be3b6 commit d585b1f

File tree

3 files changed

+55
-22
lines changed

3 files changed

+55
-22
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
2015-12-21 - Pagination support
33
2015-12-21 - Sort support
44
2015-12-21 - v1.0.0
5+
2015-12-30 - Offload queries to Mongo
6+
2015-12-30 - v1.1.0

lib/mongoHandler.js

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"use strict";
22
var _ = {
3-
clone: require("lodash.clone"),
43
omit: require("lodash.omit")
54
};
65
var async = require("async");
@@ -30,7 +29,7 @@ MongoStore._isRelationshipAttribute = function(attribute) {
3029

3130

3231
MongoStore._toMongoDocument = function(resource) {
33-
var document = _.clone(resource, true);
32+
var document = _.omit(resource, function(value) { return value === undefined; });
3433
document._id = MongoStore._mongoUuid(document.id);
3534
return document;
3635
};
@@ -49,18 +48,46 @@ MongoStore._getRelationshipAttributeNames = function(attributes) {
4948
};
5049

5150

52-
MongoStore._getSearchCriteria = function(relationships) {
53-
if (!relationships) return {};
51+
MongoStore.prototype._getSearchCriteria = function(request) {
52+
var self = this;
53+
if (!request.params.filter) return { };
54+
55+
var criteria = Object.keys(request.params.filter).map(function(attribute) {
56+
var attributeConfig = self.resourceConfig.attributes[attribute];
57+
// If the filter attribute doens't exist, skip it
58+
if (!attributeConfig) return null;
59+
60+
var values = request.params.filter[attribute];
61+
// Relationships need to be queried via .id
62+
if (attributeConfig._settings) {
63+
attribute += ".id";
64+
// Filters on nested resources should be skipped
65+
if (values instanceof Object) return null;
66+
}
5467

55-
var relationshipNames = Object.getOwnPropertyNames(relationships);
56-
var criteria = relationshipNames.reduce(function(partialCriteria, relationshipName) {
57-
var relationshipId = relationships[relationshipName];
58-
partialCriteria[relationshipName + ".id"] = relationshipId;
59-
return partialCriteria;
60-
}, {});
61-
debug("criteria>", JSON.stringify(criteria, null, 2));
68+
// Coerce values to an array to simplify the logic
69+
if (!(values instanceof Array)) values = [ values ];
70+
values = values.map(function(value) {
71+
if (value[0] === "<") return { $lt: value.substring(1) };
72+
if (value[0] === ">") return { $gt: value.substring(1) };
73+
if (value[0] === "~") return new RegExp("^" + value.substring(1) + "$", "i");
74+
if (value[0] === ":") return new RegExp(value.substring(1));
75+
return value;
76+
}).map(function(value) {
77+
var tmp = { };
78+
tmp[attribute] = value;
79+
return tmp;
80+
});
81+
82+
return { $or: values };
83+
}).filter(function(value) {
84+
return value !== null;
85+
});
6286

63-
return criteria;
87+
if (criteria.length === 0) {
88+
return { };
89+
}
90+
return { $and: criteria };
6491
};
6592

6693

@@ -95,7 +122,6 @@ MongoStore.prototype._applySort = function(request, cursor) {
95122
}
96123
var sortParam = { };
97124
sortParam[attribute] = order;
98-
debug("sort>", sortParam);
99125

100126
return cursor.sort(sortParam);
101127
};
@@ -104,7 +130,6 @@ MongoStore.prototype._applySort = function(request, cursor) {
104130
MongoStore.prototype._applyPagination = function(request, cursor) {
105131
if (!request.params.page) return cursor;
106132

107-
debug("pagination>", request.params.page.offset, request.params.page.limit);
108133
return cursor.skip(request.params.page.offset).limit(request.params.page.limit);
109134
};
110135

@@ -125,7 +150,6 @@ MongoStore.prototype.initialise = function(resourceConfig) {
125150
return console.error("error connecting to MongoDB:", err.message);
126151
}).then(function() {
127152
var resourceName = resourceConfig.resource;
128-
debug("initialising resource [" + resourceName + "]");
129153
var collection = self._db.collection(resourceName);
130154
self._createIndexesForRelationships(collection, self.relationshipAttributeNames);
131155
self.ready = true;
@@ -156,7 +180,8 @@ MongoStore.prototype.populate = function(callback) {
156180
MongoStore.prototype.search = function(request, callback) {
157181
var self = this;
158182
var collection = self._db.collection(request.params.type);
159-
var criteria = MongoStore._getSearchCriteria(request.params.relationships);
183+
var criteria = self._getSearchCriteria(request);
184+
debug("search", JSON.stringify(criteria));
160185

161186
async.parallel({
162187
resultSet: function(asyncCallback) {
@@ -180,6 +205,8 @@ MongoStore.prototype.search = function(request, callback) {
180205
MongoStore.prototype.find = function(request, callback) {
181206
var collection = this._db.collection(request.params.type);
182207
var documentId = MongoStore._mongoUuid(request.params.id);
208+
209+
debug("findOne", JSON.stringify({ _id: documentId }));
183210
collection.findOne({ _id: documentId }, { _id: 0 }, function(err, result) {
184211
if (err || !result) {
185212
return callback(MongoStore._notFoundError(request.params.type, request.params.id));
@@ -195,6 +222,7 @@ MongoStore.prototype.find = function(request, callback) {
195222
MongoStore.prototype.create = function(request, newResource, callback) {
196223
var collection = this._db.collection(newResource.type);
197224
var document = MongoStore._toMongoDocument(newResource);
225+
debug("insert", JSON.stringify(document));
198226
collection.insertOne(document, function(err) {
199227
if (err) return callback(err);
200228
collection.findOne(document, { _id: 0 }, callback);
@@ -226,7 +254,7 @@ MongoStore.prototype.update = function(request, partialResource, callback) {
226254
var collection = this._db.collection(request.params.type);
227255
var documentId = MongoStore._mongoUuid(request.params.id);
228256
var partialDocument = _.omit(partialResource, function(value) { return value === undefined; });
229-
debug("partialDocument>", JSON.stringify(partialDocument, null, 2));
257+
debug("findOneAndUpdate", JSON.stringify(partialDocument));
230258
collection.findOneAndUpdate({
231259
_id: documentId
232260
}, {
@@ -235,12 +263,16 @@ MongoStore.prototype.update = function(request, partialResource, callback) {
235263
returnOriginal: false,
236264
projection: { _id: 0 }
237265
}, function(err, result) {
238-
debug("err>", JSON.stringify(err, null, 2));
239-
debug("result>", JSON.stringify(result, null, 2));
240-
if (err) return callback(err);
266+
if (err) {
267+
debug("err", JSON.stringify(err));
268+
return callback(err);
269+
}
270+
241271
if (!result || !result.value) {
242272
return callback(MongoStore._notFoundError(request.params.type, request.params.id));
243273
}
274+
275+
debug("result", JSON.stringify(result));
244276
return callback(null, result.value);
245277
});
246278
};

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "jsonapi-store-mongodb",
3-
"version": "1.0.0",
3+
"version": "1.1.0",
44
"description": "MongoDB data store for jsonapi-server.",
55
"main": "lib/mongoHandler.js",
66
"repository": {
@@ -27,7 +27,6 @@
2727
"dependencies": {
2828
"async": "1.5.0",
2929
"debug": "2.2.0",
30-
"lodash.clone": "3.0.3",
3130
"lodash.omit": "3.1.0",
3231
"mongodb": "2.0.48"
3332
},

0 commit comments

Comments
 (0)