// Cannot implicitly shard accessed collections because of use of $near query instead of geoNear // command. // @tags: [assumes_unsharded_collection, 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}));