1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
// @tags: [requires_getmore]
// Test 2dsphere near search, called via find and geoNear.
t = db.geo_s2near;
t.drop();
// Make sure that geoNear gives us back loc
goldenPoint = {
type: "Point",
coordinates: [31.0, 41.0]
};
t.insert({geo: goldenPoint});
t.ensureIndex({geo: "2dsphere"});
resNear = db.runCommand(
{geoNear: t.getName(), near: [30, 40], num: 1, spherical: true, includeLocs: true});
assert.eq(resNear.results[0].loc, goldenPoint);
// FYI:
// One degree of long @ 0 is 111km or so.
// One degree of lat @ 0 is 110km or so.
lat = 0;
lng = 0;
points = 10;
for (var x = -points; x < points; x += 1) {
for (var y = -points; y < points; y += 1) {
t.insert({geo: {"type": "Point", "coordinates": [lng + x / 1000.0, lat + y / 1000.0]}});
}
}
origin = {
"type": "Point",
"coordinates": [lng, lat]
};
t.ensureIndex({geo: "2dsphere"});
// Near only works when the query is a point.
someline = {
"type": "LineString",
"coordinates": [[40, 5], [41, 6]]
};
somepoly = {
"type": "Polygon",
"coordinates": [[[40, 5], [40, 6], [41, 6], [41, 5], [40, 5]]]
};
assert.throws(function() {
return t.find({"geo": {"$near": {"$geometry": someline}}}).count();
});
assert.throws(function() {
return t.find({"geo": {"$near": {"$geometry": somepoly}}}).count();
});
assert.throws(function() {
return db.runCommand({geoNear: t.getName(), near: someline, spherical: true}).results.length;
});
assert.throws(function() {
return db.runCommand({geoNear: t.getName(), near: somepoly, spherical: true}).results.length;
});
// Do some basic near searches.
res = t.find({"geo": {"$near": {"$geometry": origin, $maxDistance: 2000}}}).limit(10);
resNear = db.runCommand(
{geoNear: t.getName(), near: [0, 0], num: 10, maxDistance: Math.PI, spherical: true});
assert.eq(res.itcount(), resNear.results.length, 10);
res = t.find({"geo": {"$near": {"$geometry": origin}}}).limit(10);
resNear = db.runCommand({geoNear: t.getName(), near: [0, 0], num: 10, spherical: true});
assert.eq(res.itcount(), resNear.results.length, 10);
// Find all the points!
res = t.find({"geo": {"$near": {"$geometry": origin}}}).limit(10000);
resNear = db.runCommand({geoNear: t.getName(), near: [0, 0], num: 10000, spherical: true});
assert.eq(resNear.results.length, res.itcount(), (2 * points) * (2 * points));
// longitude goes -180 to 180
// latitude goes -90 to 90
// Let's put in some perverse (polar) data and make sure we get it back.
// Points go long, lat.
t.insert({geo: {"type": "Point", "coordinates": [-180, -90]}});
t.insert({geo: {"type": "Point", "coordinates": [180, -90]}});
t.insert({geo: {"type": "Point", "coordinates": [180, 90]}});
t.insert({geo: {"type": "Point", "coordinates": [-180, 90]}});
res = t.find({"geo": {"$near": {"$geometry": origin}}}).limit(10000);
resNear = db.runCommand({geoNear: t.getName(), near: [0, 0], num: 10000, spherical: true});
assert.eq(res.itcount(), resNear.results.length, (2 * points) * (2 * points) + 4);
function testRadAndDegreesOK(distance) {
// Distance for old style points is radians.
resRadians = t.find({geo: {$nearSphere: [0, 0], $maxDistance: (distance / (6378.1 * 1000))}});
// Distance for new style points is meters.
resMeters = t.find({"geo": {"$near": {"$geometry": origin, $maxDistance: distance}}});
// And we should get the same # of results no matter what.
assert.eq(resRadians.itcount(), resMeters.itcount());
// Also, geoNear should behave the same way.
resGNMeters =
db.runCommand({geoNear: t.getName(), near: origin, maxDistance: distance, spherical: true});
resGNRadians = db.runCommand({
geoNear: t.getName(),
near: [0, 0],
maxDistance: (distance / (6378.1 * 1000)),
spherical: true
});
assert.eq(resGNRadians.results.length, resGNMeters.results.length);
for (var i = 0; i < resGNRadians.length; ++i) {
// Radius of earth * radians = distance in meters.
assert.close(resGNRadians.results[i].dis * 6378.1 * 1000, resGNMeters.results[i].dis);
}
}
testRadAndDegreesOK(1);
testRadAndDegreesOK(10);
testRadAndDegreesOK(50);
testRadAndDegreesOK(10000);
// SERVER-13666 legacy coordinates must be in bounds for spherical near queries.
assert.commandFailed(
db.runCommand({geoNear: t.getName(), near: [1210.466, 31.2051], spherical: true, num: 10}));
|