summaryrefslogtreecommitdiff
path: root/src/mongo/db/query
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/query')
-rw-r--r--src/mongo/db/query/index_bounds_builder.cpp19
-rw-r--r--src/mongo/db/query/indexability.h1
-rw-r--r--src/mongo/db/query/planner_ixselect.cpp12
-rw-r--r--src/mongo/db/query/query_planner_geo_test.cpp35
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;