The shell should attach the logical session used to initiate cursors (via find or aggregate) and use it for successive getMores.
162 lines
5.8 KiB
JavaScript
162 lines
5.8 KiB
JavaScript
// SERVER-7781 $geoNear pipeline stage
|
|
(function() {
|
|
'use strict';
|
|
|
|
load('jstests/libs/geo_near_random.js');
|
|
load('jstests/aggregation/extras/utils.js');
|
|
|
|
var coll = 'server7781';
|
|
|
|
db[coll].drop();
|
|
db[coll].insert({loc: [0, 0]});
|
|
|
|
// $geoNear is only allowed as the first stage in a pipeline, nowhere else.
|
|
assert.throws(
|
|
() => db[coll].aggregate(
|
|
[{$match: {x: 1}}, {$geoNear: {near: [1, 1], spherical: true, distanceField: 'dis'}}]));
|
|
|
|
function checkOutput(cmdOut, aggOut, expectedNum) {
|
|
assert.commandWorked(cmdOut, "geoNear command");
|
|
|
|
// the output arrays are accessed differently
|
|
cmdOut = cmdOut.results;
|
|
aggOut = aggOut.toArray();
|
|
|
|
assert.eq(cmdOut.length, expectedNum);
|
|
assert.eq(aggOut.length, expectedNum);
|
|
|
|
var allSame = true;
|
|
var massaged; // massage geoNear command output to match output from agg pipeline
|
|
for (var i = 0; i < cmdOut.length; i++) {
|
|
massaged = {};
|
|
Object.extend(massaged, cmdOut[i].obj, /*deep=*/true);
|
|
massaged.stats = {'dis': cmdOut[i].dis, 'loc': cmdOut[i].loc};
|
|
|
|
if (!friendlyEqual(massaged, aggOut[i])) {
|
|
allSame = false; // don't bail yet since we want to print all differences
|
|
print("Difference detected at index " + i + " of " + expectedNum);
|
|
print("from geoNear command:" + tojson(massaged));
|
|
print("from aggregate command:" + tojson(aggOut[i]));
|
|
}
|
|
}
|
|
|
|
assert(allSame);
|
|
}
|
|
|
|
// We use this to generate points. Using a single global to avoid reseting RNG in each pass.
|
|
var pointMaker = new GeoNearRandomTest(coll);
|
|
|
|
function test(db, sharded, indexType) {
|
|
db[coll].drop();
|
|
|
|
if (sharded) { // sharded setup
|
|
var shards = [];
|
|
var config = db.getSiblingDB("config");
|
|
config.shards.find().forEach(function(shard) {
|
|
shards.push(shard._id);
|
|
});
|
|
|
|
assert.commandWorked(
|
|
db.adminCommand({shardCollection: db[coll].getFullName(), key: {rand: 1}}));
|
|
for (var i = 1; i < 10; i++) {
|
|
// split at 0.1, 0.2, ... 0.9
|
|
assert.commandWorked(
|
|
db.adminCommand({split: db[coll].getFullName(), middle: {rand: i / 10}}));
|
|
db.adminCommand({
|
|
moveChunk: db[coll].getFullName(),
|
|
find: {rand: i / 10},
|
|
to: shards[i % shards.length]
|
|
});
|
|
}
|
|
|
|
assert.eq(config.chunks.count({'ns': db[coll].getFullName()}), 10);
|
|
}
|
|
|
|
// insert points
|
|
var numPts = 10 * 1000;
|
|
var bulk = db[coll].initializeUnorderedBulkOp();
|
|
for (var i = 0; i < numPts; i++) {
|
|
bulk.insert({rand: Math.random(), loc: pointMaker.mkPt()});
|
|
}
|
|
assert.writeOK(bulk.execute());
|
|
|
|
assert.eq(db[coll].count(), numPts);
|
|
|
|
db[coll].ensureIndex({loc: indexType});
|
|
|
|
// test with defaults
|
|
var queryPoint = pointMaker.mkPt(0.25); // stick to center of map
|
|
var geoCmd = {geoNear: coll, near: queryPoint, includeLocs: true, spherical: true};
|
|
var aggCmd = {
|
|
$geoNear: {
|
|
near: queryPoint,
|
|
includeLocs: 'stats.loc',
|
|
distanceField: 'stats.dis',
|
|
spherical: true
|
|
}
|
|
};
|
|
checkOutput(db.runCommand(geoCmd), db[coll].aggregate(aggCmd), 100);
|
|
|
|
// test with num
|
|
queryPoint = pointMaker.mkPt(0.25);
|
|
geoCmd.num = 75;
|
|
geoCmd.near = queryPoint;
|
|
aggCmd.$geoNear.num = 75;
|
|
aggCmd.$geoNear.near = queryPoint;
|
|
checkOutput(db.runCommand(geoCmd), db[coll].aggregate(aggCmd), 75);
|
|
|
|
// test with limit instead of num (they mean the same thing, but want to test both)
|
|
queryPoint = pointMaker.mkPt(0.25);
|
|
geoCmd.near = queryPoint;
|
|
delete geoCmd.num;
|
|
geoCmd.limit = 70;
|
|
aggCmd.$geoNear.near = queryPoint;
|
|
delete aggCmd.$geoNear.num;
|
|
aggCmd.$geoNear.limit = 70;
|
|
checkOutput(db.runCommand(geoCmd), db[coll].aggregate(aggCmd), 70);
|
|
|
|
// test spherical
|
|
queryPoint = pointMaker.mkPt(0.25);
|
|
geoCmd.spherical = true;
|
|
geoCmd.near = queryPoint;
|
|
aggCmd.$geoNear.spherical = true;
|
|
aggCmd.$geoNear.near = queryPoint;
|
|
checkOutput(db.runCommand(geoCmd), db[coll].aggregate(aggCmd), 70);
|
|
|
|
// test $geoNear + $limit coalescing
|
|
queryPoint = pointMaker.mkPt(0.25);
|
|
geoCmd.num = 40;
|
|
geoCmd.near = queryPoint;
|
|
aggCmd.$geoNear.near = queryPoint;
|
|
var aggArr = [aggCmd, {$limit: 50}, {$limit: 60}, {$limit: 40}];
|
|
checkOutput(db.runCommand(geoCmd), db[coll].aggregate(aggArr), 40);
|
|
|
|
// Test $geoNear with an initial batchSize of 0. Regression test for SERVER-20935.
|
|
queryPoint = pointMaker.mkPt(0.25);
|
|
geoCmd.spherical = true;
|
|
geoCmd.near = queryPoint;
|
|
geoCmd.limit = 70;
|
|
delete geoCmd.num;
|
|
aggCmd.$geoNear.spherical = true;
|
|
aggCmd.$geoNear.near = queryPoint;
|
|
aggCmd.$geoNear.limit = 70;
|
|
delete aggCmd.$geoNear.num;
|
|
var cmdRes = db[coll].runCommand("aggregate", {pipeline: [aggCmd], cursor: {batchSize: 0}});
|
|
assert.commandWorked(cmdRes);
|
|
var cmdCursor = new DBCommandCursor(db, cmdRes, 0);
|
|
checkOutput(db.runCommand(geoCmd), cmdCursor, 70);
|
|
}
|
|
|
|
test(db, false, '2d');
|
|
test(db, false, '2dsphere');
|
|
|
|
var sharded = new ShardingTest({shards: 3, mongos: 1});
|
|
assert.commandWorked(sharded.s0.adminCommand({enablesharding: "test"}));
|
|
sharded.ensurePrimaryShard('test', 'shard0001');
|
|
|
|
test(sharded.getDB('test'), true, '2d');
|
|
test(sharded.getDB('test'), true, '2dsphere');
|
|
|
|
sharded.stop();
|
|
})();
|