-
Type: Bug
-
Resolution: Fixed
-
Priority: Major - P3
-
Affects Version/s: 4.2.3, 4.0.17
-
Component/s: Aggregation Framework, Querying
-
None
-
Fully Compatible
-
ALL
-
v4.4, v4.2, v4.0
-
Query 2020-04-20, Query 2020-05-04, Query 2020-05-18, Query 2020-06-01, Query 2020-06-15, Query 2020-06-29
Prior to MongoDB 4.2 (4.1.1 specifically) the $geoNear aggregation stage was internally issuing a geoNear command through the
DBDirect client. With SERVER-35043 the geoNear command was removed and the necessary logic merged into the aggregation stage.
MongoDB 4.0.17
2020-03-31T07:44:58.950-0400 I COMMAND [conn7] command admin.foo appName: "MongoDB Shell" command: geoNear { geoNear: "foo", near: { coordinates: [ 106.65589, 10.787627 ], type: "Point" }, num: 100, query: { _id: { $in: [ "1", "2", "3" ] }, state: "ACTIVE" }, collation: { locale: "simple" }, spherical: true, distanceMultiplier: 1.0, key: "location", $db: "admin" } planSummary: GEO_NEAR_2DSPHERE { _id: 1, location: "2dsphere", state: 1 } keysExamined:0 docsExamined:0 numYields:0 reslen:128 locks:{ Global: { acquireCount: { r: 2 } }, Database: { acquireCount: { r: 2 } }, Collection: { acquireCount: { r: 2 } } } protocol:op_msg 0ms
2020-03-31T07:44:58.951-0400 I COMMAND [conn7] command admin.foo appName: "MongoDB Shell" command: aggregate { aggregate: "foo", pipeline: [ { $geoNear: { query: { _id: { $in: [ "1", "2", "3" ] }, state: "ACTIVE" }, spherical: true, near: { coordinates: [ 106.65589, 10.787627 ], type: "Point" }, distanceField: "distance", key: "location" } }, { $project: { id: 1.0, name: 1.0 } } ], hint: { _id: 1.0, location: "2dsphere", state: 1.0 }, cursor: {}, lsid: { id: UUID("46e819d1-9d58-43ed-aee0-97d37cd0ba09") }, $db: "admin" } keysExamined:0 docsExamined:0 cursorExhausted:1 numYields:0 nreturned:0 reslen:98 locks:{ Global: { acquireCount: { r: 2 } }, Database: { acquireCount: { r: 2 } }, Collection: { acquireCount: { r: 2 } } } protocol:op_msg 2ms
Given the two log lines shared you can see that the initial geoNear command has chosen a different index than what was hinted to the pipeline. This appears to be due to how the call from DocumentSourceGeoNear::runCommand() is building the command (see DocumentSourceGeoNear::buildGeoNearCmd()). The underlying geoNear command does not appear to take the hint from the pipeline when it is constructed so the query planner has to decide which index to use.
This bug affects the geoNear command as well when it is invoked directly.
MongoDB 4.2.5
2020-04-01T09:53:34.479-0400 I COMMAND [conn3] command admin.foo command: aggregate { aggregate: "foo", pipeline: [ { $geoNear: { query: { _id: { $in: [ "1", "2", "3" ] }, state: "ACTIVE" }, spherical: true, near: { coordinates: [ 106.65589, 10.787627 ], type: "Point" }, distanceField: "distance", key: "location" } }, { $project: { id: 1.0, name: 1.0, distance: 1.0 } } ], cursor: {}, $db: "admin", $readPreference: { mode: "primaryPreferred" } } planSummary: IXSCAN { location: "2dsphere" }, IXSCAN { location: "2dsphere" }, IXSCAN { location: "2dsphere" }, IXSCAN { location: "2dsphere" }, IXSCAN { location: "2dsphere" }, IXSCAN { location: "2dsphere" }, IXSCAN { location: "2dsphere" } keysExamined:7 docsExamined:2 fromMultiPlanner:1 cursorExhausted:1 numYields:0 nreturned:1 queryHash:54B91EED planCacheKey:B1991E01 reslen:150 locks:{ ReplicationStateTransition: { acquireCount: { w: 2 } }, Global: { acquireCount: { r: 2 } }, Database: { acquireCount: { r: 2 } }, Collection: { acquireCount: { r: 2 } }, Mutex: { acquireCount: { r: 2 } } } storage:{ data: { bytesRead: 223 } } protocol:op_msg 3ms
Even once the geoNear command is no longer in use (MongoDB 4.2) the pipeline stage still discards the hint (it is not logged either).
Note that this behavior can be reproduced as follows:
db.setProfilingLevel(0, { slowms: 0 }) db.foo.drop(); db.foo.insert({ _id: "1", state: "ACTIVE", location: [106, 10], name: "TEST" }) db.foo.createIndex({ location: "2dsphere" }) db.foo.createIndex({ _id: 1, location: "2dsphere", state: 1 }); db.foo.aggregate([ { $geoNear: { query: { _id: { $in: ["1", "2", "3"] }, state: "ACTIVE" }, spherical: true, near: { coordinates: [106.65589, 10.787627], type: "Point" }, distanceField: "distance", key: "location" }}, { $project: { id: 1, name: 1, distance: 1 }}], { hint: { _id: 1, location: "2dsphere", state: 1}});