Skip to content

Commit 7122ca0

Browse files
jlnqueredplewis
authored andcommitted
Fix issue on count with Geo constraints and mongo (issue #5285) (#5286)
* Add a tests that fails due to issue #5285 * Make test code much simpler * Fix #5285 by rewriting query (replacing $nearSphere by $geoWithin) All credit goes to @dplewis ! * move logic to transform
1 parent 7e130c5 commit 7122ca0

File tree

3 files changed

+73
-16
lines changed

3 files changed

+73
-16
lines changed

spec/ParseGeoPoint.spec.js

+47-3
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,8 @@ describe('Parse.GeoPoint testing', () => {
1111
obj.set('location', point);
1212
obj.set('name', 'Ferndale');
1313
await obj.save();
14-
const results = await new Parse.Query(TestObject).find();
15-
equal(results.length, 1);
16-
const pointAgain = results[0].get('location');
14+
const result = await new Parse.Query(TestObject).get(obj.id);
15+
const pointAgain = result.get('location');
1716
ok(pointAgain);
1817
equal(pointAgain.latitude, 44.0);
1918
equal(pointAgain.longitude, -11.0);
@@ -727,4 +726,49 @@ describe('Parse.GeoPoint testing', () => {
727726
done();
728727
});
729728
});
729+
730+
it('withinKilometers supports count', async () => {
731+
const inside = new Parse.GeoPoint(10, 10);
732+
const outside = new Parse.GeoPoint(20, 20);
733+
734+
const obj1 = new Parse.Object('TestObject', { location: inside });
735+
const obj2 = new Parse.Object('TestObject', { location: outside });
736+
737+
await Parse.Object.saveAll([obj1, obj2]);
738+
739+
const q = new Parse.Query(TestObject).withinKilometers(
740+
'location',
741+
inside,
742+
5
743+
);
744+
const count = await q.count();
745+
746+
equal(count, 1);
747+
});
748+
749+
it('withinKilometers complex supports count', async () => {
750+
const inside = new Parse.GeoPoint(10, 10);
751+
const middle = new Parse.GeoPoint(20, 20);
752+
const outside = new Parse.GeoPoint(30, 30);
753+
const obj1 = new Parse.Object('TestObject', { location: inside });
754+
const obj2 = new Parse.Object('TestObject', { location: middle });
755+
const obj3 = new Parse.Object('TestObject', { location: outside });
756+
757+
await Parse.Object.saveAll([obj1, obj2, obj3]);
758+
759+
const q1 = new Parse.Query(TestObject).withinKilometers(
760+
'location',
761+
inside,
762+
5
763+
);
764+
const q2 = new Parse.Query(TestObject).withinKilometers(
765+
'location',
766+
middle,
767+
5
768+
);
769+
const query = Parse.Query.or(q1, q2);
770+
const count = await query.count();
771+
772+
equal(count, 2);
773+
});
730774
});

src/Adapters/Storage/Mongo/MongoStorageAdapter.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ export class MongoStorageAdapter implements StorageAdapter {
690690
readPreference = this._parseReadPreference(readPreference);
691691
return this._adaptiveCollection(className)
692692
.then(collection =>
693-
collection.count(transformWhere(className, query, schema), {
693+
collection.count(transformWhere(className, query, schema, true), {
694694
maxTimeMS: this._maxTimeMS,
695695
readPreference,
696696
})

src/Adapters/Storage/Mongo/MongoTransform.js

+25-12
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ const valueAsDate = value => {
224224
return false;
225225
};
226226

227-
function transformQueryKeyValue(className, key, value, schema) {
227+
function transformQueryKeyValue(className, key, value, schema, count = false) {
228228
switch (key) {
229229
case 'createdAt':
230230
if (valueAsDate(value)) {
@@ -293,7 +293,7 @@ function transformQueryKeyValue(className, key, value, schema) {
293293
return {
294294
key: key,
295295
value: value.map(subQuery =>
296-
transformWhere(className, subQuery, schema)
296+
transformWhere(className, subQuery, schema, count)
297297
),
298298
};
299299
case 'lastUsed':
@@ -330,7 +330,7 @@ function transformQueryKeyValue(className, key, value, schema) {
330330
}
331331

332332
// Handle query constraints
333-
const transformedConstraint = transformConstraint(value, field);
333+
const transformedConstraint = transformConstraint(value, field, count);
334334
if (transformedConstraint !== CannotTransform) {
335335
if (transformedConstraint.$text) {
336336
return { key: '$text', value: transformedConstraint.$text };
@@ -359,14 +359,15 @@ function transformQueryKeyValue(className, key, value, schema) {
359359
// Main exposed method to help run queries.
360360
// restWhere is the "where" clause in REST API form.
361361
// Returns the mongo form of the query.
362-
function transformWhere(className, restWhere, schema) {
362+
function transformWhere(className, restWhere, schema, count = false) {
363363
const mongoWhere = {};
364364
for (const restKey in restWhere) {
365365
const out = transformQueryKeyValue(
366366
className,
367367
restKey,
368368
restWhere[restKey],
369-
schema
369+
schema,
370+
count
370371
);
371372
mongoWhere[out.key] = out.value;
372373
}
@@ -816,7 +817,7 @@ function relativeTimeToDate(text, now = new Date()) {
816817
// If it is not a valid constraint but it could be a valid something
817818
// else, return CannotTransform.
818819
// inArray is whether this is an array field.
819-
function transformConstraint(constraint, field) {
820+
function transformConstraint(constraint, field, count = false) {
820821
const inArray = field && field.type && field.type === 'Array';
821822
if (typeof constraint !== 'object' || !constraint) {
822823
return CannotTransform;
@@ -1002,15 +1003,27 @@ function transformConstraint(constraint, field) {
10021003
}
10031004
break;
10041005
}
1005-
case '$nearSphere':
1006-
var point = constraint[key];
1007-
answer[key] = [point.longitude, point.latitude];
1006+
case '$nearSphere': {
1007+
const point = constraint[key];
1008+
if (count) {
1009+
answer.$geoWithin = {
1010+
$centerSphere: [
1011+
[point.longitude, point.latitude],
1012+
constraint.$maxDistance,
1013+
],
1014+
};
1015+
} else {
1016+
answer[key] = [point.longitude, point.latitude];
1017+
}
10081018
break;
1009-
1010-
case '$maxDistance':
1019+
}
1020+
case '$maxDistance': {
1021+
if (count) {
1022+
break;
1023+
}
10111024
answer[key] = constraint[key];
10121025
break;
1013-
1026+
}
10141027
// The SDKs don't seem to use these but they are documented in the
10151028
// REST API docs.
10161029
case '$maxDistanceInRadians':

0 commit comments

Comments
 (0)