diff options
Diffstat (limited to 'jstests/aggregation/sources/geonear/distancefield_and_includelocs.js')
-rw-r--r-- | jstests/aggregation/sources/geonear/distancefield_and_includelocs.js | 319 |
1 files changed, 158 insertions, 161 deletions
diff --git a/jstests/aggregation/sources/geonear/distancefield_and_includelocs.js b/jstests/aggregation/sources/geonear/distancefield_and_includelocs.js index 80e884c2c36..1ed2364ccb3 100644 --- a/jstests/aggregation/sources/geonear/distancefield_and_includelocs.js +++ b/jstests/aggregation/sources/geonear/distancefield_and_includelocs.js @@ -3,167 +3,164 @@ * (specifically, by specifying nested fields, overriding existing fields, and so on). */ (function() { - "use strict"; - - load("jstests/aggregation/extras/utils.js"); // For 'customDocumentEq'. - - const coll = db.getCollection("geonear_distancefield_and_includelocs"); - coll.drop(); - - /** - * Runs an aggregation with a $geoNear stage using 'geoSpec' and an optional $project stage - * using 'projSpec'. Returns the first result; that is, the result closest to the "near" point. - */ - function firstGeoNearResult(geoSpec, projSpec) { - geoSpec.spherical = true; - const pipeline = [{$geoNear: geoSpec}, {$limit: 1}]; - if (projSpec) { - pipeline.push({$project: projSpec}); - } - - const res = coll.aggregate(pipeline).toArray(); - assert.eq(1, res.length, tojson(res)); - return res[0]; +"use strict"; + +load("jstests/aggregation/extras/utils.js"); // For 'customDocumentEq'. + +const coll = db.getCollection("geonear_distancefield_and_includelocs"); +coll.drop(); + +/** + * Runs an aggregation with a $geoNear stage using 'geoSpec' and an optional $project stage + * using 'projSpec'. Returns the first result; that is, the result closest to the "near" point. + */ +function firstGeoNearResult(geoSpec, projSpec) { + geoSpec.spherical = true; + const pipeline = [{$geoNear: geoSpec}, {$limit: 1}]; + if (projSpec) { + pipeline.push({$project: projSpec}); } - // Use documents with a variety of different fields: scalars, arrays, legacy points and GeoJSON - // objects. - const docWithLegacyPoint = { - _id: "legacy", - geo: [1, 1], - ptForNearQuery: [1, 1], - scalar: "foo", - arr: [{a: 1, b: 1}, {a: 2, b: 2}], - }; - const docWithGeoPoint = { - _id: "point", - geo: {type: "Point", coordinates: [1, 0]}, - ptForNearQuery: [1, 0], - scalar: "bar", - arr: [{a: 3, b: 3}, {a: 4, b: 4}], - }; - const docWithGeoLine = { - _id: "linestring", - geo: {type: "LineString", coordinates: [[0, 0], [-1, -1]]}, - ptForNearQuery: [-1, -1], - scalar: "baz", - arr: [{a: 5, b: 5}, {a: 6, b: 6}], - }; - - // We test with a 2dsphere index, since 2d indexes can't support GeoJSON objects. - assert.commandWorked(coll.createIndex({geo: "2dsphere"})); - - // Populate the collection. - assert.writeOK(coll.insert(docWithLegacyPoint)); - assert.writeOK(coll.insert(docWithGeoPoint)); - assert.writeOK(coll.insert(docWithGeoLine)); - - // Define a custom way to compare documents since the results here might differ by insignificant - // amounts. - const assertCloseEnough = (left, right) => - assert(customDocumentEq({ - left: left, - right: right, - valueComparator: (a, b) => { - if (typeof a !== "number") { - return a === b; - } - // Allow some minor differences in the numbers. - return Math.abs(a - b) < 1e-10; - } - }), - () => `[${tojson(left)}] != [${tojson(right)}]`); - - [docWithLegacyPoint, docWithGeoPoint, docWithGeoLine].forEach(doc => { - const docPlusNewFields = (newDoc) => Object.extend(Object.extend({}, doc), newDoc); - - // - // Tests for "distanceField". - // - const expectedDistance = 0.0000000000000001; - - // Test that "distanceField" can be computed in a new field. - assertCloseEnough(firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "newField"}), - docPlusNewFields({newField: expectedDistance})); - - // Test that "distanceField" can be computed in a new nested field. - assertCloseEnough( - firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "nested.field"}), - docPlusNewFields({nested: {field: expectedDistance}})); - - // Test that "distanceField" can overwrite an existing scalar field. - assertCloseEnough(firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "scalar"}), - docPlusNewFields({scalar: expectedDistance})); - - // Test that "distanceField" can completely overwrite an existing array field. - assertCloseEnough(firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "arr"}), - docPlusNewFields({arr: expectedDistance})); - - // TODO (SERVER-35561): When "includeLocs" shares a path prefix with an existing field, the - // fields are overwritten, even if they could be preserved. - assertCloseEnough(firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "arr.b"}), - docPlusNewFields({arr: {b: expectedDistance}})); - - // - // Tests for both "includeLocs" and "distanceField". - // - - // Test that "distanceField" and "includeLocs" can both be specified. - assertCloseEnough( - firstGeoNearResult( - {near: doc.ptForNearQuery, distanceField: "dist", includeLocs: "loc"}), - docPlusNewFields({dist: expectedDistance, loc: doc.geo})); - - // Test that "distanceField" and "includeLocs" can be the same path. The result is arbitrary - // ("includeLocs" wins). - assertCloseEnough( - firstGeoNearResult( - {near: doc.ptForNearQuery, distanceField: "newField", includeLocs: "newField"}), - docPlusNewFields({newField: doc.geo})); - - // Test that "distanceField" and "includeLocs" are both preserved when their paths share a - // prefix but do not conflict. - assertCloseEnough( - firstGeoNearResult( - {near: doc.ptForNearQuery, distanceField: "comp.dist", includeLocs: "comp.loc"}), - docPlusNewFields({comp: {dist: expectedDistance, loc: doc.geo}})); - - // - // Tests for "includeLocs" only. Project out the distance field. - // - const removeDistFieldProj = {d: 0}; - - // Test that "includeLocs" can be computed in a new field. - assertCloseEnough( - firstGeoNearResult( - {near: doc.ptForNearQuery, distanceField: "d", includeLocs: "newField"}, - removeDistFieldProj), - docPlusNewFields({newField: doc.geo})); - - // Test that "includeLocs" can be computed in a new nested field. - assertCloseEnough( - firstGeoNearResult( - {near: doc.ptForNearQuery, distanceField: "d", includeLocs: "nested.field"}, - removeDistFieldProj), - docPlusNewFields({nested: {field: doc.geo}})); - - // Test that "includeLocs" can overwrite an existing scalar field. - assertCloseEnough(firstGeoNearResult( - {near: doc.ptForNearQuery, distanceField: "d", includeLocs: "scalar"}, - removeDistFieldProj), - docPlusNewFields({scalar: doc.geo})); - - // Test that "includeLocs" can completely overwrite an existing array field. - assertCloseEnough( - firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "d", includeLocs: "arr"}, - removeDistFieldProj), - docPlusNewFields({arr: doc.geo})); - - // TODO (SERVER-35561): When "includeLocs" shares a path prefix with an existing field, the - // fields are overwritten, even if they could be preserved. - assertCloseEnough( - firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "d", includeLocs: "arr.a"}, - removeDistFieldProj), - docPlusNewFields({arr: {a: doc.geo}})); - }); + const res = coll.aggregate(pipeline).toArray(); + assert.eq(1, res.length, tojson(res)); + return res[0]; +} + +// Use documents with a variety of different fields: scalars, arrays, legacy points and GeoJSON +// objects. +const docWithLegacyPoint = { + _id: "legacy", + geo: [1, 1], + ptForNearQuery: [1, 1], + scalar: "foo", + arr: [{a: 1, b: 1}, {a: 2, b: 2}], +}; +const docWithGeoPoint = { + _id: "point", + geo: {type: "Point", coordinates: [1, 0]}, + ptForNearQuery: [1, 0], + scalar: "bar", + arr: [{a: 3, b: 3}, {a: 4, b: 4}], +}; +const docWithGeoLine = { + _id: "linestring", + geo: {type: "LineString", coordinates: [[0, 0], [-1, -1]]}, + ptForNearQuery: [-1, -1], + scalar: "baz", + arr: [{a: 5, b: 5}, {a: 6, b: 6}], +}; + +// We test with a 2dsphere index, since 2d indexes can't support GeoJSON objects. +assert.commandWorked(coll.createIndex({geo: "2dsphere"})); + +// Populate the collection. +assert.writeOK(coll.insert(docWithLegacyPoint)); +assert.writeOK(coll.insert(docWithGeoPoint)); +assert.writeOK(coll.insert(docWithGeoLine)); + +// Define a custom way to compare documents since the results here might differ by insignificant +// amounts. +const assertCloseEnough = (left, right) => assert(customDocumentEq({ + left: left, + right: right, + valueComparator: (a, b) => { + if (typeof a !== "number") { + return a === b; + } + // Allow some minor differences in the + // numbers. + return Math.abs(a - b) < 1e-10; + } + }), + () => `[${tojson(left)}] != [${tojson(right)}]`); + +[docWithLegacyPoint, docWithGeoPoint, docWithGeoLine].forEach(doc => { + const docPlusNewFields = (newDoc) => Object.extend(Object.extend({}, doc), newDoc); + + // + // Tests for "distanceField". + // + const expectedDistance = 0.0000000000000001; + + // Test that "distanceField" can be computed in a new field. + assertCloseEnough(firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "newField"}), + docPlusNewFields({newField: expectedDistance})); + + // Test that "distanceField" can be computed in a new nested field. + assertCloseEnough(firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "nested.field"}), + docPlusNewFields({nested: {field: expectedDistance}})); + + // Test that "distanceField" can overwrite an existing scalar field. + assertCloseEnough(firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "scalar"}), + docPlusNewFields({scalar: expectedDistance})); + + // Test that "distanceField" can completely overwrite an existing array field. + assertCloseEnough(firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "arr"}), + docPlusNewFields({arr: expectedDistance})); + + // TODO (SERVER-35561): When "includeLocs" shares a path prefix with an existing field, the + // fields are overwritten, even if they could be preserved. + assertCloseEnough(firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "arr.b"}), + docPlusNewFields({arr: {b: expectedDistance}})); + + // + // Tests for both "includeLocs" and "distanceField". + // + + // Test that "distanceField" and "includeLocs" can both be specified. + assertCloseEnough( + firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "dist", includeLocs: "loc"}), + docPlusNewFields({dist: expectedDistance, loc: doc.geo})); + + // Test that "distanceField" and "includeLocs" can be the same path. The result is arbitrary + // ("includeLocs" wins). + assertCloseEnough( + firstGeoNearResult( + {near: doc.ptForNearQuery, distanceField: "newField", includeLocs: "newField"}), + docPlusNewFields({newField: doc.geo})); + + // Test that "distanceField" and "includeLocs" are both preserved when their paths share a + // prefix but do not conflict. + assertCloseEnough( + firstGeoNearResult( + {near: doc.ptForNearQuery, distanceField: "comp.dist", includeLocs: "comp.loc"}), + docPlusNewFields({comp: {dist: expectedDistance, loc: doc.geo}})); + + // + // Tests for "includeLocs" only. Project out the distance field. + // + const removeDistFieldProj = {d: 0}; + + // Test that "includeLocs" can be computed in a new field. + assertCloseEnough( + firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "d", includeLocs: "newField"}, + removeDistFieldProj), + docPlusNewFields({newField: doc.geo})); + + // Test that "includeLocs" can be computed in a new nested field. + assertCloseEnough( + firstGeoNearResult( + {near: doc.ptForNearQuery, distanceField: "d", includeLocs: "nested.field"}, + removeDistFieldProj), + docPlusNewFields({nested: {field: doc.geo}})); + + // Test that "includeLocs" can overwrite an existing scalar field. + assertCloseEnough( + firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "d", includeLocs: "scalar"}, + removeDistFieldProj), + docPlusNewFields({scalar: doc.geo})); + + // Test that "includeLocs" can completely overwrite an existing array field. + assertCloseEnough( + firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "d", includeLocs: "arr"}, + removeDistFieldProj), + docPlusNewFields({arr: doc.geo})); + + // TODO (SERVER-35561): When "includeLocs" shares a path prefix with an existing field, the + // fields are overwritten, even if they could be preserved. + assertCloseEnough( + firstGeoNearResult({near: doc.ptForNearQuery, distanceField: "d", includeLocs: "arr.a"}, + removeDistFieldProj), + docPlusNewFields({arr: {a: doc.geo}})); +}); }()); |