Skip to content

Commit 9b9dc92

Browse files
committed
1 parent 28de236 commit 9b9dc92

File tree

6 files changed

+346
-68
lines changed

6 files changed

+346
-68
lines changed

lib/query.js

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ function Query (criteria, options) {
3030
this._conditions = {};
3131
this._updateArg = {};
3232
this._fields = undefined;
33+
this._geoComparison = undefined;
3334
if (criteria) this.find(criteria);
3435
}
3536

@@ -301,7 +302,8 @@ Query.prototype.cast = function (model, obj) {
301302

302303
var geo = val.$near ? '$near' :
303304
val.$nearSphere ? '$nearSphere' :
304-
val.$within ? '$within' : '';
305+
val.$within ? '$within' :
306+
val.$geoIntersects ? '$geoIntersects' : '';
305307

306308
if (!geo) {
307309
continue;
@@ -316,12 +318,23 @@ Query.prototype.cast = function (model, obj) {
316318

317319
if ('$within' == geo) {
318320
// find $center, $centerSphere, $box, $polygon
319-
var withinType = value.$center || value.$centerSphere || value.$box || value.$polygon;
321+
var withinType = value.$center || value.$centerSphere || value.$box || value.$polygon// || value.$geometry;
320322
if (!withinType) {
321323
throw new Error('Bad $within paramater: ' + JSON.stringify(val));
322324
}
323325

324326
value = withinType;
327+
328+
} else if ('$near' == geo &&
329+
'string' == typeof value.type && Array.isArray(value.coordinates)) {
330+
// geojson; cast the coordinates
331+
value = value.coordinates;
332+
333+
} else if (('$near' == geo || '$geoIntersects' == geo) &&
334+
value.$geometry && 'string' == typeof value.$geometry.type &&
335+
Array.isArray(value.$geometry.coordinates)) {
336+
// geojson; cast the coordinates
337+
value = value.$geometry.coordinates;
325338
}
326339

327340
;(function _cast (val) {
@@ -976,7 +989,34 @@ Query.prototype.elemMatch = function (path, criteria) {
976989
*/
977990

978991
Object.defineProperty(Query.prototype, 'within', {
979-
get: function () { return this }
992+
get: function () {
993+
this._geoComparison = '$within';
994+
return this
995+
}
996+
});
997+
998+
/**
999+
* Declares an intersects query for `geometry()`.
1000+
*
1001+
* ####Example
1002+
*
1003+
* query.intersects.geometry({
1004+
* type: 'LineString'
1005+
* , coordinates: [[180.0, 11.0], [180, 9.0]]
1006+
* })
1007+
*
1008+
* @property intersects
1009+
* @see Query#geometry #query_Query-geometry
1010+
* @memberOf Query
1011+
* @return {Query} this
1012+
* @api public
1013+
*/
1014+
1015+
Object.defineProperty(Query.prototype, 'intersects', {
1016+
get: function () {
1017+
this._geoComparison = '$geoIntersects';
1018+
return this
1019+
}
9801020
});
9811021

9821022
/**
@@ -1092,6 +1132,57 @@ Query.prototype.polygon = function (path, val) {
10921132
return this;
10931133
};
10941134

1135+
/**
1136+
* Specifies a $geometry condition
1137+
*
1138+
* Accepts an object that must contain the following two properties:
1139+
*
1140+
* - type: `String`
1141+
* - coordinates: `Array`
1142+
*
1143+
* ####Example
1144+
*
1145+
* var polyA = [[[ 10, 20 ], [ 10, 40 ], [ 30, 40 ], [ 30, 20 ]]]
1146+
* query.where('loc').within.geometry({ type: 'Polygon', coordinates: polyA })
1147+
*
1148+
* // or
1149+
* var polyB = [[ 0, 0 ], [ 1, 1 ]]
1150+
* query.where('loc').within.geometry({ type: 'LineString', coordinates: polyB })
1151+
*
1152+
* // or
1153+
* var polyC = [ 0, 0 ]
1154+
* query.where('loc').within.geometry({ type: 'Point', coordinates: polyC })
1155+
*
1156+
* // or
1157+
* var polyC = [ 0, 0 ]
1158+
* query.where('loc').intersects.geometry({ type: 'Point', coordinates: polyC })
1159+
*
1160+
* _NOTE: Must come after `intersects` or `within`._
1161+
*
1162+
* @param {String} [path]
1163+
* @param {Object} obj
1164+
* @return {Query} this
1165+
* @see http://docs.mongodb.org/manual/release-notes/2.4/#new-geospatial-indexes-with-geojson-and-improved-spherical-geometry
1166+
* @see http://www.mongodb.org/display/DOCS/Geospatial+Indexing
1167+
* @api public
1168+
*/
1169+
1170+
Query.prototype.geometry = function (path, val) {
1171+
if (arguments.length === 1) {
1172+
val = path;
1173+
path = this._currPath;
1174+
}
1175+
1176+
var conds = this._conditions[path] || (this._conditions[path] = {});
1177+
1178+
if (!this._geoComparison) {
1179+
throw new Error('query.geometry() must come after either `within` or `intersects`');
1180+
}
1181+
1182+
conds[this._geoComparison] = { $geometry: val };
1183+
return this;
1184+
};
1185+
10951186
/**
10961187
* Specifies which document fields to include or exclude
10971188
*

lib/schema.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -675,10 +675,10 @@ Schema.prototype.get = function (key) {
675675

676676
Schema.prototype.indexes = function () {
677677
var indexes = []
678-
, seenSchemas = [];
678+
, seenSchemas = []
679+
, indexTypes = '2d 2dsphere'.split(' ');
679680

680681
collectIndexes(this);
681-
682682
return indexes;
683683

684684
function collectIndexes (schema, prefix) {
@@ -696,10 +696,10 @@ Schema.prototype.indexes = function () {
696696
} else {
697697
index = paths[i]._index;
698698

699-
if (index !== false && index !== null){
699+
if (index !== false && index !== null) {
700700
var field = {};
701-
field[prefix + i] = '2d' === index ? index : 1;
702-
var options = 'Object' === index.constructor.name ? index : {};
701+
field[prefix + i] = ~indexTypes.indexOf(index) ? index : 1;
702+
var options = utils.isObject(index) ? index : {};
703703
if (!('background' in options)) options.background = true;
704704
indexes.push([field, options]);
705705
}

lib/schema/array.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,18 @@ function castToNumber (val) {
190190
return Types.Number.prototype.cast.call(this, val);
191191
}
192192

193+
function castArray (arr, self) {
194+
self || (self = this);
195+
196+
arr.forEach(function (v, i) {
197+
if (Array.isArray(v)) {
198+
castArray(v, self);
199+
} else {
200+
arr[i] = castToNumber.call(self, v);
201+
}
202+
});
203+
}
204+
193205
SchemaArray.prototype.$conditionalHandlers = {
194206
'$all': function handle$all (val) {
195207
if (!Array.isArray(val)) {
@@ -255,10 +267,36 @@ SchemaArray.prototype.$conditionalHandlers = {
255267
val[type][i] = castToNumber.call(this, item);
256268
}
257269
})
270+
} else if (val.$geometry) {
271+
switch (val.$geometry.type) {
272+
case 'Polygon':
273+
case 'LineString':
274+
case 'Point':
275+
val.$geometry.coordinates.forEach(castArray);
276+
break;
277+
default:
278+
// ignore unknowns
279+
break;
280+
}
258281
}
259282

260283
return val;
261284
}
285+
, '$geoIntersects': function (val) {
286+
var geo = val.$geometry;
287+
if (!geo) return;
288+
289+
switch (val.$geometry.type) {
290+
case 'Polygon':
291+
case 'LineString':
292+
case 'Point':
293+
val.$geometry.coordinates.forEach(castArray);
294+
break;
295+
default:
296+
// ignore unknowns
297+
break;
298+
}
299+
}
262300
, '$maxDistance': castToNumber
263301
};
264302

lib/schema/number.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ function handleSingle (val) {
144144

145145
function handleArray (val) {
146146
var self = this;
147-
return val.map( function (m) {
147+
return val.map(function (m) {
148148
return self.cast(m)
149149
});
150150
}

test/common.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,28 @@ module.exports = function (options) {
9898
};
9999

100100
/**
101-
* Module exports.
101+
* expose mongoose
102102
*/
103103

104104
module.exports.mongoose = mongoose;
105+
106+
/**
107+
* expose mongod version helper
108+
*/
109+
110+
module.exports.mongodVersion = function (cb) {
111+
var db = module.exports();
112+
113+
db.on('error', cb);
114+
115+
db.on('open', function () {
116+
db.db.admin(function (err, admin) {
117+
if (err) return cb(err);
118+
admin.serverStatus(function (err, info) {
119+
if (err) return cb(err);
120+
var version = info.version.split('.').map(function(n){return parseInt(n, 10) });
121+
cb(null, version);
122+
});
123+
});
124+
})
125+
}

0 commit comments

Comments
 (0)