Skip to content

Commit 7b9ebc4

Browse files
NotBobTheBuilderflovilmart
authored andcommitted
Avoid multiple $nears in one query (#3798)
Mongo has a hard limit on 1 $near operation per query. Restructuring to avoid SERVER-13732 should not invalidate a query by creating multiple $near operations. Additionally, queries with multiple $ors are now recursively handled, whereas before, ops at the top level would only have been pushed one level deeper. #3767
1 parent 64e6f40 commit 7b9ebc4

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

spec/DatabaseController.spec.js

+23
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,29 @@ describe('DatabaseController', function() {
1313
done();
1414
});
1515

16+
it('should not restructure SERVER-13732 queries with $nears', (done) => {
17+
var query = {$or: [{a: 1}, {b: 1}], c: {$nearSphere: {}}};
18+
validateQuery(query);
19+
expect(query).toEqual({$or: [{a: 1}, {b: 1}], c: {$nearSphere: {}}});
20+
21+
query = {$or: [{a: 1}, {b: 1}], c: {$near: {}}};
22+
validateQuery(query);
23+
expect(query).toEqual({$or: [{a: 1}, {b: 1}], c: {$near: {}}});
24+
25+
done();
26+
});
27+
28+
29+
it('should push refactored keys down a tree for SERVER-13732', (done) => {
30+
var query = {a: 1, $or: [{$or: [{b: 1}, {b: 2}]},
31+
{$or: [{c: 1}, {c: 2}]}]};
32+
validateQuery(query);
33+
expect(query).toEqual({$or: [{$or: [{b: 1, a: 1}, {b: 2, a: 1}]},
34+
{$or: [{c: 1, a: 1}, {c: 2, a: 1}]}]});
35+
36+
done();
37+
});
38+
1639
it('should reject invalid queries', (done) => {
1740
expect(() => validateQuery({$or: {'a': 1}})).toThrow();
1841
done();

src/Controllers/DatabaseController.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -69,17 +69,27 @@ const validateQuery = query => {
6969
* EG: {$or: [{a: 1}, {a: 2}], b: 2}
7070
* Becomes: {$or: [{a: 1, b: 2}, {a: 2, b: 2}]}
7171
*
72+
* The only exceptions are $near and $nearSphere operators, which are
73+
* constrained to only 1 operator per query. As a result, these ops
74+
* remain at the top level
75+
*
7276
* https://jira.mongodb.org/browse/SERVER-13732
77+
* https://github.com/parse-community/parse-server/issues/3767
7378
*/
7479
Object.keys(query).forEach(key => {
7580
const noCollisions = !query.$or.some(subq => subq.hasOwnProperty(key))
76-
if (key != '$or' && noCollisions) {
81+
let hasNears = false
82+
if (query[key] != null && typeof query[key] == 'object') {
83+
hasNears = ('$near' in query[key] || '$nearSphere' in query[key])
84+
}
85+
if (key != '$or' && noCollisions && !hasNears) {
7786
query.$or.forEach(subquery => {
7887
subquery[key] = query[key];
7988
});
8089
delete query[key];
8190
}
8291
});
92+
query.$or.forEach(validateQuery);
8393
} else {
8494
throw new Parse.Error(Parse.Error.INVALID_QUERY, 'Bad $or format - use an array value.');
8595
}

0 commit comments

Comments
 (0)