// @tags: [ // assumes_balancer_off, // requires_fastcount, // ] t = db.geo_center_sphere1; function test(index) { t.drop(); skip = 8; // lower for more rigor, higher for more speed (tested with .5, .678, 1, 2, 3, and 4) searches = [ // x , y rad [[5, 0], 0.05], // ~200 miles [[135, 0], 0.05], [[5, 70], 0.05], [[135, 70], 0.05], [[5, 85], 0.05], [[20, 0], 0.25], // ~1000 miles [[20, -45], 0.25], [[-20, 60], 0.25], [[-20, -70], 0.25], ]; correct = searches.map(function(z) { return []; }); num = 0; var bulk = t.initializeUnorderedBulkOp(); for (x = -179; x <= 179; x += skip) { for (y = -89; y <= 89; y += skip) { o = {_id: num++, loc: [x, y]}; bulk.insert(o); for (i = 0; i < searches.length; i++) { if (Geo.sphereDistance([x, y], searches[i][0]) <= searches[i][1]) correct[i].push(o); } } gc(); // needed with low skip values } assert.commandWorked(bulk.execute()); if (index) { t.createIndex({loc: index}); } for (i = 0; i < searches.length; i++) { print('------------'); print(tojson(searches[i]) + "\t" + correct[i].length); q = {loc: {$within: {$centerSphere: searches[i]}}}; // correct[i].forEach( printjson ) // printjson( q ); // t.find( q ).forEach( printjson ) // printjson(t.find( q ).explain()) // printjson( Array.sort( correct[i].map( function(z){ return z._id; } ) ) ) // printjson( Array.sort( t.find(q).map( function(z){ return z._id; } ) ) ) var numExpected = correct[i].length; var x = correct[i].map(function(z) { return z._id; }); var y = t.find(q).map(function(z) { return z._id; }); missing = []; epsilon = 0.001; // allow tenth of a percent error due to conversions for (var j = 0; j < x.length; j++) { if (!Array.contains(y, x[j])) { missing.push(x[j]); var obj = t.findOne({_id: x[j]}); var dist = Geo.sphereDistance(searches[i][0], obj.loc); print("missing: " + tojson(obj) + " " + dist); if ((Math.abs(dist - searches[i][1]) / dist) < epsilon) numExpected -= 1; } } for (var j = 0; j < y.length; j++) { if (!Array.contains(x, y[j])) { missing.push(y[j]); var obj = t.findOne({_id: y[j]}); var dist = Geo.sphereDistance(searches[i][0], obj.loc); print("extra: " + tojson(obj) + " " + dist); if ((Math.abs(dist - searches[i][1]) / dist) < epsilon) numExpected += 1; } } assert.eq(numExpected, t.find(q).itcount(), "itcount : " + tojson(searches[i])); assert.eq(numExpected, t.find(q).count(), "count : " + tojson(searches[i])); if (index == "2d") { var explain = t.find(q).explain("executionStats"); print('explain for ' + tojson(q, '', true) + ' = ' + tojson(explain)); // The index should be at least minimally effective in preventing the full collection // scan. assert.gt(t.find().count(), explain.executionStats.totalKeysExamined, "nscanned : " + tojson(searches[i])); } } } test("2d"); test("2dsphere"); test(false);