diff options
Diffstat (limited to 'src/mongo/db/query')
-rw-r--r-- | src/mongo/db/query/index_bounds_builder.cpp | 19 | ||||
-rw-r--r-- | src/mongo/db/query/indexability.h | 1 | ||||
-rw-r--r-- | src/mongo/db/query/planner_ixselect.cpp | 12 | ||||
-rw-r--r-- | src/mongo/db/query/query_planner_geo_test.cpp | 35 |
4 files changed, 66 insertions, 1 deletions
diff --git a/src/mongo/db/query/index_bounds_builder.cpp b/src/mongo/db/query/index_bounds_builder.cpp index 4176823172e..505d1096fba 100644 --- a/src/mongo/db/query/index_bounds_builder.cpp +++ b/src/mongo/db/query/index_bounds_builder.cpp @@ -41,6 +41,7 @@ #include "mongo/db/index/expression_params.h" #include "mongo/db/index/s2_common.h" #include "mongo/db/matcher/expression_geo.h" +#include "mongo/db/matcher/expression_internal_bucket_geo_within.h" #include "mongo/db/matcher/expression_internal_expr_comparison.h" #include "mongo/db/query/collation/collation_index_key.h" #include "mongo/db/query/collation/collator_interface.h" @@ -1015,6 +1016,24 @@ void IndexBoundsBuilder::_translatePredicate(const MatchExpression* expr, "element"_attr = elt.toString()); verify(0); } + } else if (MatchExpression::INTERNAL_BUCKET_GEO_WITHIN == expr->matchType()) { + const InternalBucketGeoWithinMatchExpression* ibgwme = + static_cast<const InternalBucketGeoWithinMatchExpression*>(expr); + if ("2dsphere_bucket"_sd == elt.valueStringDataSafe()) { + tassert(5837101, + "A geo query on a sphere must have an S2 region", + ibgwme->getGeoContainer()->hasS2Region()); + const S2Region& region = ibgwme->getGeoContainer()->getS2Region(); + S2IndexingParams indexParams; + ExpressionParams::initialize2dsphereParams(index.infoObj, index.collator, &indexParams); + ExpressionMapping::cover2dsphere(region, indexParams, oilOut); + *tightnessOut = IndexBoundsBuilder::INEXACT_FETCH; + } else { + LOGV2_WARNING(5837102, + "Planner error trying to build bucketed geo bounds for an index element", + "element"_attr = elt.toString()); + MONGO_UNREACHABLE_TASSERT(5837103); + } } else { LOGV2_WARNING(20935, "Planner error while trying to build bounds for expression", diff --git a/src/mongo/db/query/indexability.h b/src/mongo/db/query/indexability.h index 96930df7650..7e543da4a2d 100644 --- a/src/mongo/db/query/indexability.h +++ b/src/mongo/db/query/indexability.h @@ -173,6 +173,7 @@ private: me->matchType() == MatchExpression::MATCH_IN || me->matchType() == MatchExpression::TYPE_OPERATOR || me->matchType() == MatchExpression::GEO || + me->matchType() == MatchExpression::INTERNAL_BUCKET_GEO_WITHIN || me->matchType() == MatchExpression::GEO_NEAR || me->matchType() == MatchExpression::EXISTS || me->matchType() == MatchExpression::TEXT || diff --git a/src/mongo/db/query/planner_ixselect.cpp b/src/mongo/db/query/planner_ixselect.cpp index 83ec4b99fe9..5abd13eddeb 100644 --- a/src/mongo/db/query/planner_ixselect.cpp +++ b/src/mongo/db/query/planner_ixselect.cpp @@ -40,6 +40,7 @@ #include "mongo/db/index_names.h" #include "mongo/db/matcher/expression_algo.h" #include "mongo/db/matcher/expression_geo.h" +#include "mongo/db/matcher/expression_internal_bucket_geo_within.h" #include "mongo/db/matcher/expression_internal_expr_comparison.h" #include "mongo/db/matcher/expression_text.h" #include "mongo/db/query/canonical_query_encoder.h" @@ -397,7 +398,8 @@ bool QueryPlannerIXSelect::_compatible(const BSONElement& keyPatternElt, } // We can't use a btree-indexed field for geo expressions. - if (exprtype == MatchExpression::GEO || exprtype == MatchExpression::GEO_NEAR) { + if (exprtype == MatchExpression::GEO || exprtype == MatchExpression::GEO_NEAR || + exprtype == MatchExpression::INTERNAL_BUCKET_GEO_WITHIN) { return false; } @@ -551,6 +553,14 @@ bool QueryPlannerIXSelect::_compatible(const BSONElement& keyPatternElt, return gnme->getData().centroid->crs == SPHERE; } return false; + } else if (IndexNames::GEO_2DSPHERE_BUCKET == indexedFieldType) { + if (exprtype == MatchExpression::INTERNAL_BUCKET_GEO_WITHIN) { + const InternalBucketGeoWithinMatchExpression* ibgwme = + static_cast<InternalBucketGeoWithinMatchExpression*>(node); + auto gc = ibgwme->getGeoContainer(); + return gc->hasS2Region(); + } + return false; } else if (IndexNames::GEO_2D == indexedFieldType) { if (exprtype == MatchExpression::GEO_NEAR) { GeoNearMatchExpression* gnme = static_cast<GeoNearMatchExpression*>(node); diff --git a/src/mongo/db/query/query_planner_geo_test.cpp b/src/mongo/db/query/query_planner_geo_test.cpp index 7028e4d57a7..6452f130042 100644 --- a/src/mongo/db/query/query_planner_geo_test.cpp +++ b/src/mongo/db/query/query_planner_geo_test.cpp @@ -1766,6 +1766,41 @@ TEST_F(QueryPlannerTest, 2dsphereNonNearWithInternalExprEqOverTrailingFieldMulti "b: [['MinKey','MaxKey',true,true]]}}}}}"); } +TEST_F(QueryPlannerTest, 2dsphereBucketWithInternalBucketGeoWithin) { + params.options = QueryPlannerParams::NO_TABLE_SCAN; + addIndex(BSON("data.a" + << "2dsphere_bucket"), + false); + + runQuery( + fromjson("{$_internalBucketGeoWithin: {withinRegion: {$centerSphere: [[0, 0], 10]}, field: " + "\"a\"}}")); + + // This query will generate complex bounds, so we relax the checks to make the test readable. + relaxBoundsCheckingToSubsetOnly(); + + assertNumSolutions(1U); + assertSolutionExists( + "{fetch: {filter: {$_internalBucketGeoWithin: {withinRegion: {$centerSphere: [[0,0],10]}, " + "field: 'a'}}," + "node: {ixscan: {pattern: {'data.a' : '2dsphere_bucket'}, filter: null, bounds:" + "{'data.a': []" // Complex, so leaving empty. + "}}}}}"); +} + +TEST_F(QueryPlannerTest, 2dsphereBucketWithInternalBucketGeoWithin2dGeneratesCollScan) { + params.options = QueryPlannerParams::NO_TABLE_SCAN; + addIndex(BSON("data.a" + << "2dsphere_bucket"), + false); + + // This query should not produce bounds. + runInvalidQuery( + fromjson("{$_internalBucketGeoWithin: {withinRegion: {$center: [[0, 0], 10]}, field: " + "\"a\"}}")); + ASSERT_EQUALS(plannerStatus.code(), ErrorCodes::NoQueryExecutionPlans); +} + TEST_F(QueryPlannerTest, 2dWithinPredicateOverTrailingFieldElemMatchMultikey) { params.options = QueryPlannerParams::NO_TABLE_SCAN; |