diff --git a/src/mongo/db/matcher/expression_geo.cpp b/src/mongo/db/matcher/expression_geo.cpp index 2129662560..66a7fa8fc9 100644 --- a/src/mongo/db/matcher/expression_geo.cpp +++ b/src/mongo/db/matcher/expression_geo.cpp @@ -48,15 +48,7 @@ namespace mongo { GeoExpression::GeoExpression() : field(""), predicate(INVALID) {} GeoExpression::GeoExpression(const std::string& f) : field(f), predicate(INVALID) {} -Status GeoExpression::parseQuery(const BSONObj& obj) { - BSONObjIterator outerIt(obj); - // "within" / "geoWithin" / "geoIntersects" - BSONElement queryElt = outerIt.next(); - if (outerIt.more()) { - return Status(ErrorCodes::BadValue, - str::stream() << "can't parse extra field: " << outerIt.next()); - } - +Status GeoExpression::parseQuery(const BSONElement& queryElt) { auto keyword = MatchExpressionParser::parsePathAcceptingKeyword(queryElt); if (PathAcceptingKeyword::GEO_INTERSECTS == keyword) { predicate = GeoExpression::INTERSECT; @@ -65,7 +57,7 @@ Status GeoExpression::parseQuery(const BSONObj& obj) { } else { // eoo() or unknown query predicate. return Status(ErrorCodes::BadValue, - str::stream() << "invalid geo query predicate: " << obj); + str::stream() << "invalid geo query predicate: " << queryElt); } // Parse geometry after predicates. @@ -79,7 +71,7 @@ Status GeoExpression::parseQuery(const BSONObj& obj) { BSONElement elt = geoIt.next(); if (elt.fieldNameStringData() == "$uniqueDocs") { // Deprecated "$uniqueDocs" field - LOGV2_WARNING(23847, "Deprecated $uniqueDocs option", "query"_attr = redact(obj)); + LOGV2_WARNING(23847, "Deprecated $uniqueDocs option", "query"_attr = redact(queryElt)); } else { // The element must be a geo specifier. "$box", "$center", "$geometry", etc. geoContainer.reset(new GeometryContainer()); @@ -96,9 +88,9 @@ Status GeoExpression::parseQuery(const BSONObj& obj) { return Status::OK(); } -Status GeoExpression::parseFrom(const BSONObj& obj) { +Status GeoExpression::parseFrom(const BSONElement& element) { // Initialize geoContainer and parse BSON object - Status status = parseQuery(obj); + Status status = parseQuery(element); if (!status.isOK()) return status; @@ -114,7 +106,7 @@ Status GeoExpression::parseFrom(const BSONObj& obj) { // this for now. if (GeoExpression::WITHIN == predicate && !geoContainer->supportsContains()) { return Status(ErrorCodes::BadValue, - str::stream() << "$within not supported with provided geometry: " << obj); + str::stream() << "$within not supported with provided geometry: " << element); } // Big polygon with strict winding order is represented as an S2Loop in SPHERE CRS. @@ -133,7 +125,7 @@ Status GeoExpression::parseFrom(const BSONObj& obj) { if (!geoContainer->supportsProject(SPHERE)) { return Status(ErrorCodes::BadValue, str::stream() - << "$geoIntersect not supported with provided geometry: " << obj); + << "$geoIntersect not supported with provided geometry: " << element); } geoContainer->projectInto(SPHERE); } diff --git a/src/mongo/db/matcher/expression_geo.h b/src/mongo/db/matcher/expression_geo.h index 39411f1ecd..b21e38b64f 100644 --- a/src/mongo/db/matcher/expression_geo.h +++ b/src/mongo/db/matcher/expression_geo.h @@ -53,7 +53,7 @@ public: enum Predicate { WITHIN, INTERSECT, INVALID }; // parseFrom() must be called before getGeometry() to ensure initialization of geoContainer - Status parseFrom(const BSONObj& obj); + Status parseFrom(const BSONElement&); std::string getField() const { return field; @@ -69,7 +69,7 @@ private: // Parse geospatial query // e.g. // { "$intersect" : { "$geometry" : { "type" : "Point", "coordinates": [ 40, 5 ] } } } - Status parseQuery(const BSONObj& obj); + Status parseQuery(const BSONElement&); // Name of the field in the query. std::string field; diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp index 434955fcf9..05fc3455a4 100644 --- a/src/mongo/db/matcher/expression_parser.cpp +++ b/src/mongo/db/matcher/expression_parser.cpp @@ -1126,22 +1126,24 @@ StatusWithMatchExpression parseInternalSchemaMatchArrayIndex( StatusWithMatchExpression parseGeo(StringData name, PathAcceptingKeyword type, - const BSONObj& section, + const BSONElement geoElement, + const BSONObj& surroundingObjectSection, const boost::intrusive_ptr& expCtx, MatchExpressionParser::AllowedFeatureSet allowedFeatures) { if (PathAcceptingKeyword::WITHIN == type || PathAcceptingKeyword::GEO_INTERSECTS == type) { auto gq = std::make_unique(name.toString()); - auto parseStatus = gq->parseFrom(section); + auto parseStatus = gq->parseFrom(geoElement); if (!parseStatus.isOK()) { return parseStatus; } - auto operatorName = section.firstElementFieldName(); + auto operatorName = geoElement.fieldName(); expCtx->sbeCompatible = false; return {std::make_unique( name, gq.release(), - section, - doc_validation_error::createAnnotation(expCtx, operatorName, BSON(name << section)))}; + surroundingObjectSection, + doc_validation_error::createAnnotation( + expCtx, operatorName, BSON(name << geoElement.wrap())))}; } else { invariant(PathAcceptingKeyword::GEO_NEAR == type); @@ -1151,12 +1153,13 @@ StatusWithMatchExpression parseGeo(StringData name, } auto nq = std::make_unique(name.toString()); - auto status = nq->parseFrom(section); + auto status = nq->parseFrom(surroundingObjectSection); if (!status.isOK()) { return status; } expCtx->sbeCompatible = false; - return {std::make_unique(name, nq.release(), section)}; + return { + std::make_unique(name, nq.release(), surroundingObjectSection)}; } } @@ -1691,7 +1694,7 @@ StatusWithMatchExpression parseSubField(const BSONObj& context, case PathAcceptingKeyword::WITHIN: case PathAcceptingKeyword::GEO_INTERSECTS: - return parseGeo(name, *parseExpMatchType, context, expCtx, allowedFeatures); + return parseGeo(name, *parseExpMatchType, e, context, expCtx, allowedFeatures); case PathAcceptingKeyword::GEO_NEAR: return {Status(ErrorCodes::BadValue, @@ -1951,8 +1954,8 @@ Status parseSub(StringData name, if (firstElt.isABSONObj()) { if (MatchExpressionParser::parsePathAcceptingKeyword(firstElt) == PathAcceptingKeyword::GEO_NEAR) { - auto s = - parseGeo(name, PathAcceptingKeyword::GEO_NEAR, sub, expCtx, allowedFeatures); + auto s = parseGeo( + name, PathAcceptingKeyword::GEO_NEAR, firstElt, sub, expCtx, allowedFeatures); if (s.isOK()) { root->add(s.getValue().release()); }