Beispiel #1
0
    bool GeoParser::parseCap(const BSONObj& obj, CapWithCRS *out) {
        if (isLegacyCenter(obj)) {
            BSONObjIterator typeIt(obj);
            BSONElement type = typeIt.next();
            BSONObjIterator objIt(type.embeddedObject());
            BSONElement center = objIt.next();
            if (!parseLegacyPoint(center.Obj(), &out->circle.center)) { return false; }
            BSONElement radius = objIt.next();
            out->circle.radius = radius.number();
            out->crs = FLAT;
        } else {
            verify(isLegacyCenterSphere(obj));
            BSONObjIterator typeIt(obj);
            BSONElement type = typeIt.next();
            BSONObjIterator objIt(type.embeddedObject());
            BSONObj centerObj = objIt.next().Obj();

            S2Point centerPoint;
            BSONObjIterator it(centerObj);
            BSONElement x = it.next();
            BSONElement y = it.next();
            centerPoint = coordToPoint(x.Number(), y.Number());
            BSONElement radiusElt = objIt.next();
            double radius = radiusElt.number();
            out->cap = S2Cap::FromAxisAngle(centerPoint, S1Angle::Radians(radius));
            out->circle.radius = radius;
            out->circle.center = Point(x.Number(), y.Number());
            out->crs = SPHERE;
        }
        return true;
    }
Beispiel #2
0
    bool GeoParser::parsePointWithMaxDistance(const BSONObj& obj, PointWithCRS* out, double* maxOut) {
        BSONObjIterator it(obj);
        if (!it.more()) { return false; }

        BSONElement lng = it.next();
        if (!lng.isNumber()) { return false; }
        if (!it.more()) { return false; }

        BSONElement lat = it.next();
        if (!lat.isNumber()) { return false; }
        if (!it.more()) { return false; }

        BSONElement dist = it.next();
        if (!dist.isNumber()) { return false; }
        if (it.more()) { return false; }

        out->crs = FLAT;
        out->oldPoint.x = lng.number();
        out->oldPoint.y = lat.number();
        *maxOut = dist.number();
        if (isValidLngLat(lng.Number(), lat.Number())) {
            out->flatUpgradedToSphere = true;
            out->point = coordToPoint(lng.Number(), lat.Number());
            out->cell = S2Cell(out->point);
        }
        return true;
    }
Beispiel #3
0
   // PD_TRACE_DECLARE_FUNCTION ( SDB__RTNREELECT_INIT, "_rtnReelect::init" )
   INT32 _rtnReelect::init ( INT32 flags, INT64 numToSkip,
                             INT64 numToReturn,
                             const CHAR *pMatcherBuff,
                             const CHAR *pSelectBuff,
                             const CHAR *pOrderByBuff,
                             const CHAR *pHintBuff )
   {
      INT32 rc = SDB_OK ;
      PD_TRACE_ENTRY( SDB__RTNREELECT_INIT ) ;
      BSONObj obj ;
      try
      {
         obj = BSONObj( pMatcherBuff ) ;
         BSONElement e = obj.getField( FIELD_NAME_REELECTION_TIMEOUT ) ;
         if ( !e.eoo() )
         {
            if ( !e.isNumber() )
            {
               PD_LOG( PDERROR, "invalid reelection msg:%s",
                       obj.toString( FALSE, TRUE ).c_str() ) ;
               rc = SDB_INVALIDARG ;
               goto error ;
            }
            _timeout = e.Number() ;
         }

         e = obj.getField( FIELD_NAME_REELECTION_LEVEL ) ;
         if ( !e.eoo() )
         {
            if ( !e.isNumber() )
            {
               PD_LOG( PDERROR, "invalid reelection msg:%s",
                       obj.toString( FALSE, TRUE ).c_str() ) ;
               rc = SDB_INVALIDARG ;
               goto error ;
            }
            _level = ( CLS_REELECTION_LEVEL )((INT32)e.Number()) ;
         }
      }
      catch ( std::exception &e )
      {
         PD_LOG( PDERROR, "unexpected error happened:%s", e.what() ) ;
         rc = SDB_SYS ;
         goto error ;
      }
   done:
      PD_TRACE_EXITRC( SDB__RTNREELECT_INIT, rc ) ;
      return rc ;
   error:
      goto done ;
   }
Beispiel #4
0
void ExpressionParams::parseTwoDParams(const BSONObj& infoObj, TwoDIndexingParams* out) {
    BSONObjIterator i(infoObj.getObjectField("key"));

    while (i.more()) {
        BSONElement e = i.next();
        if (e.type() == String && IndexNames::GEO_2D == e.valuestr()) {
            uassert(16800, "can't have 2 geo fields", out->geo.size() == 0);
            uassert(16801, "2d has to be first in index", out->other.size() == 0);
            out->geo = e.fieldName();
        } else {
            int order = 1;
            if (e.isNumber()) {
                order = static_cast<int>(e.Number());
            }
            out->other.push_back(std::make_pair(e.fieldName(), order));
        }
    }

    uassert(16802, "no geo field specified", out->geo.size());

    GeoHashConverter::Parameters hashParams;
    Status paramStatus = GeoHashConverter::parseParameters(infoObj, &hashParams);
    uassertStatusOK(paramStatus);

    out->geoHashConverter.reset(new GeoHashConverter(hashParams));
}
Beispiel #5
0
        bool parseLegacy(const BSONObj &obj, QueryGeometry *out, bool *isNear, bool *intersect,
                         double *maxDistance) const {
            // Legacy intersect parsing: t.find({ loc : [0,0] })
            if (out->parseFrom(obj)) {
                *isNear = true;
                return true;
            }

            bool ret = false;
            BSONObjIterator it(obj);
            while (it.more()) {
                BSONElement e = it.next();
                if (!e.isABSONObj()) { return false; }
                BSONObj embeddedObj = e.embeddedObject();
                // Legacy near parsing: t.find({ loc : { $near: [0,0], $maxDistance: 3 }})
                // Legacy near parsing: t.find({ loc : { $near: [0,0] }})
                if (mongoutils::str::equals(e.fieldName(), "$near")) {
                    if (out->parseFrom(embeddedObj)) {
                        uassert(16573, "near requires point, given " + embeddedObj.toString(),
                                GeoParser::isPoint(embeddedObj));
                        *isNear = true;
                        ret = true;
                    }
                } else if (mongoutils::str::equals(e.fieldName(), "$maxDistance")) {
                    *maxDistance = e.Number();
                }
            }
            return ret;
        }
Beispiel #6
0
 // PD_TRACE_DECLARE_FUNCTION ( SDB__RTNFORCESTEPUP_INIT, "_rtnForceStepUp::init" )
 INT32 _rtnForceStepUp::init( INT32 flags, INT64 numToSkip,
                              INT64 numToReturn,
                              const CHAR *pMatcherBuff,
                              const CHAR *pSelectBuff,
                              const CHAR *pOrderByBuff,
                              const CHAR *pHintBuff )
 {
    INT32 rc = SDB_OK ;
    PD_TRACE_ENTRY( SDB__RTNFORCESTEPUP_INIT ) ;
    BSONObj options ;
    try
    {
       options = BSONObj( pMatcherBuff ).copy() ;
       BSONElement e = options.getField( FIELD_NAME_FORCE_STEP_UP_TIME ) ;
       if ( e.isNumber() )
       {
          _seconds = e.Number() ;
       }
    }
    catch ( std::exception &e )
    {
       PD_LOG( PDERROR, "unexpected error happened:%s", e.what() ) ;
       rc = SDB_SYS ;
       goto error ;
    }
 done:
    PD_TRACE_EXITRC( SDB__RTNFORCESTEPUP_INIT, rc ) ;
    return rc ;
 error:
    goto done ;
 }
Beispiel #7
0
bool GeoNearExpression::parseLegacyQuery(const BSONObj& obj) {
    bool hasGeometry = false;

    // First, try legacy near, e.g.:
    // t.find({ loc : { $nearSphere: [0,0], $minDistance: 1, $maxDistance: 3 }})
    // t.find({ loc : { $nearSphere: [0,0] }})
    // t.find({ loc : { $near : [0, 0, 1] } });
    // t.find({ loc : { $near: { someGeoJSONPoint}})
    // t.find({ loc : { $geoNear: { someGeoJSONPoint}})
    BSONObjIterator it(obj);
    while (it.more()) {
        BSONElement e = it.next();
        if (equals(e.fieldName(), "$near") || equals(e.fieldName(), "$geoNear") ||
            equals(e.fieldName(), "$nearSphere")) {
            if (!e.isABSONObj()) {
                return false;
            }
            BSONObj embeddedObj = e.embeddedObject();

            if (GeoParser::parseQueryPoint(e, centroid.get()).isOK() ||
                GeoParser::parsePointWithMaxDistance(embeddedObj, centroid.get(), &maxDistance)) {
                uassert(18522, "max distance must be non-negative", maxDistance >= 0.0);
                hasGeometry = true;
                isNearSphere = equals(e.fieldName(), "$nearSphere");
            }
        } else if (equals(e.fieldName(), "$minDistance")) {
            uassert(16893, "$minDistance must be a number", e.isNumber());
            minDistance = e.Number();
            uassert(16894, "$minDistance must be non-negative", minDistance >= 0.0);
        } else if (equals(e.fieldName(), "$maxDistance")) {
            uassert(16895, "$maxDistance must be a number", e.isNumber());
            maxDistance = e.Number();
            uassert(16896, "$maxDistance must be non-negative", maxDistance >= 0.0);
        } else if (equals(e.fieldName(), "$uniqueDocs")) {
            warning() << "ignoring deprecated option $uniqueDocs";
        } else {
            // In a query document, $near queries can have no non-geo sibling parameters.
            uasserted(34413,
                      str::stream() << "invalid argument in geo near query: " << e.fieldName());
        }
    }

    return hasGeometry;
}
 bool GeoParser::parsePoint(const BSONObj &obj, PointWithCRS *out) {
     if (isLegacyPoint(obj, true)) {
         BSONObjIterator it(obj);
         BSONElement x = it.next();
         BSONElement y = it.next();
         out->oldPoint.x = x.Number();
         out->oldPoint.y = y.Number();
         out->crs = FLAT;
     } else if (isGeoJSONPoint(obj)) {
         const vector<BSONElement>& coords = obj.getFieldDotted(GEOJSON_COORDINATES).Array();
         out->oldPoint.x = coords[0].Number();
         out->oldPoint.y = coords[1].Number();
         out->crs = FLAT;
         if (!ShapeProjection::supportsProject(*out, SPHERE))
             return false;
         ShapeProjection::projectInto(out, SPHERE);
     }
     return true;
 }
Beispiel #9
0
 static bool isLegacyCenterSphere(const BSONObj &obj) {
     BSONObjIterator typeIt(obj);
     BSONElement type = typeIt.next();
     if (!type.isABSONObj()) { return false; }
     bool isCenterSphere = mongoutils::str::equals(type.fieldName(), "$centerSphere");
     if (!isCenterSphere) { return false; }
     BSONObjIterator objIt(type.embeddedObject());
     BSONElement center = objIt.next();
     if (!center.isABSONObj()) { return false; }
     if (!isLegacyPoint(center.Obj())) { return false; }
     // Check to make sure the points are valid lng/lat.
     BSONObjIterator coordIt(center.Obj());
     BSONElement lng = coordIt.next();
     BSONElement lat = coordIt.next();
     if (!isValidLngLat(lng.Number(), lat.Number())) { return false; }
     if (!objIt.more()) { return false; }
     BSONElement radius = objIt.next();
     if (!radius.isNumber()) { return false; }
     return true;
 }
Beispiel #10
0
bool NearQuery::parseLegacyQuery(const BSONObj &obj) {

    bool hasGeometry = false;

    // First, try legacy near, e.g.:
    // t.find({ loc : { $nearSphere: [0,0], $minDistance: 1, $maxDistance: 3 }})
    // t.find({ loc : { $nearSphere: [0,0] }})
    // t.find({ loc : { $near : [0, 0, 1] } });
    // t.find({ loc : { $near: { someGeoJSONPoint}})
    // t.find({ loc : { $geoNear: { someGeoJSONPoint}})
    BSONObjIterator it(obj);
    while (it.more()) {
        BSONElement e = it.next();
        if (equals(e.fieldName(), "$near") || equals(e.fieldName(), "$geoNear")
                || equals(e.fieldName(), "$nearSphere")) {
            if (!e.isABSONObj()) {
                return false;
            }
            BSONObj embeddedObj = e.embeddedObject();

            if ((GeoParser::isPoint(embeddedObj) && GeoParser::parsePoint(embeddedObj, &centroid))
                    || GeoParser::parsePointWithMaxDistance(embeddedObj, &centroid, &maxDistance)) {
                uassert(18522, "max distance must be non-negative", maxDistance >= 0.0);
                hasGeometry = true;
                isNearSphere = equals(e.fieldName(), "$nearSphere");
            }
        } else if (equals(e.fieldName(), "$minDistance")) {
            uassert(16893, "$minDistance must be a number", e.isNumber());
            minDistance = e.Number();
            uassert(16894, "$minDistance must be non-negative", minDistance >= 0.0);
        } else if (equals(e.fieldName(), "$maxDistance")) {
            uassert(16895, "$maxDistance must be a number", e.isNumber());
            maxDistance = e.Number();
            uassert(16896, "$maxDistance must be non-negative", maxDistance >= 0.0);
        } else if (equals(e.fieldName(), "$uniqueDocs")) {
            warning() << "ignoring deprecated option $uniqueDocs";
        }
    }

    return hasGeometry;
}
Beispiel #11
0
    bool GeoParser::parsePoint(const BSONObj &obj, PointWithCRS *out) {
        if (isGeoJSONPoint(obj)) {
            const vector<BSONElement>& coords = obj.getFieldDotted(GEOJSON_COORDINATES).Array();
            out->point = coordToPoint(coords[0].Number(), coords[1].Number());
            out->cell = S2Cell(out->point);
            out->oldPoint.x = coords[0].Number();
            out->oldPoint.y = coords[1].Number(); 
            out->crs = SPHERE;
        } else if (isLegacyPoint(obj)) {
            BSONObjIterator it(obj);
            BSONElement x = it.next();
            BSONElement y = it.next();
            out->point = coordToPoint(x.Number(), y.Number());
            out->cell = S2Cell(out->point);
            out->oldPoint.x = x.Number();
            out->oldPoint.y = y.Number(); 
            out->crs = FLAT;
        }

        return true;
    }
Beispiel #12
0
bool BatchedCommandRequest::isVerboseWC() const {
    if (!isWriteConcernSet()) {
        return true;
    }

    BSONObj writeConcern = getWriteConcern();
    BSONElement wElem = writeConcern["w"];
    if (!wElem.isNumber() || wElem.Number() != 0) {
        return true;
    }

    return false;
}
/* ****************************************************************************
*
* addCompoundNode -
*
*/
static void addCompoundNode(orion::CompoundValueNode* cvP, const BSONElement& e)
{
  if ((e.type() != String) && (e.type() != Bool) && (e.type() != NumberDouble) && (e.type() != jstNULL) && (e.type() != Object) && (e.type() != Array))
  {
    LM_E(("Runtime Error (unknown BSON type: %d)", e.type()));
    return;
  }

  orion::CompoundValueNode* child = new orion::CompoundValueNode(orion::ValueTypeObject);
  child->name = dbDotDecode(e.fieldName());

  switch (e.type())
  {
  case String:
    child->valueType  = orion::ValueTypeString;
    child->stringValue = e.String();
    break;

  case Bool:
    child->valueType  = orion::ValueTypeBoolean;
    child->boolValue = e.Bool();
    break;

  case NumberDouble:
    child->valueType  = orion::ValueTypeNumber;
    child->numberValue = e.Number();
    break;

  case jstNULL:
    child->valueType  = orion::ValueTypeNone;
    break;

  case Object:
    compoundObjectResponse(child, e);
    break;

  case Array:
    compoundVectorResponse(child, e);
    break;

  default:
    //
    // We need the default clause to avoid 'enumeration value X not handled in switch' errors
    // due to -Werror=switch at compilation time
    //
    break;
  }

  cvP->add(child);
}
Beispiel #14
0
        bool parseQuery(const BSONObj &obj, QueryGeometry *out, bool *isNear, bool *intersect,
                        double *maxDistance) const {
            // pointA = { "type" : "Point", "coordinates": [ 40, 5 ] }
            // t.find({ "geo" : { "$intersect" : { "$geometry" : pointA} } })
            // t.find({ "geo" : { "$near" : { "$geometry" : pointA, $maxDistance : 20 }}})
            // where field.name is "geo"
            BSONElement e = obj.firstElement();
            if (!e.isABSONObj()) { return false; }

            BSONObj::MatchType matchType = static_cast<BSONObj::MatchType>(e.getGtLtOp());
            if (BSONObj::opGEO_INTERSECTS == matchType) {
                *intersect = true;
            } else if (BSONObj::opNEAR == matchType) {
                *isNear = true;
            } else {
                return false;
            }

            bool ret = false;
            BSONObjIterator argIt(e.embeddedObject());
            while (argIt.more()) {
                BSONElement e = argIt.next();
                if (mongoutils::str::equals(e.fieldName(), "$geometry")) {
                    if (e.isABSONObj()) {
                        BSONObj embeddedObj = e.embeddedObject();
                         if (out->parseFrom(embeddedObj)) {
                             uassert(16570, "near requires point, given " + embeddedObj.toString(),
                                     !(*isNear) || GeoParser::isPoint(embeddedObj));
                             ret = true;
                         }
                    }
                } else if (mongoutils::str::equals(e.fieldName(), "$maxDistance")) {
                    if (e.isNumber()) {
                        *maxDistance = e.Number();
                    }
                }
            }
            return ret;
        }
Beispiel #15
0
    TwoDAccessMethod::TwoDAccessMethod(BtreeInMemoryState* btreeState)
        : BtreeBasedAccessMethod(btreeState) {

        const IndexDescriptor* descriptor = btreeState->descriptor();

        BSONObjIterator i(descriptor->keyPattern());
        while (i.more()) {
            BSONElement e = i.next();
            if (e.type() == String && IndexNames::GEO_2D == e.valuestr()) {
                uassert(16800, "can't have 2 geo fields", _params.geo.size() == 0);
                uassert(16801, "2d has to be first in index", _params.other.size() == 0);
                _params.geo = e.fieldName();
            } else {
                int order = 1;
                if (e.isNumber()) {
                    order = static_cast<int>(e.Number());
                }
                _params.other.push_back(make_pair(e.fieldName(), order));
            }
        }
        uassert(16802, "no geo field specified", _params.geo.size());

        double bits =  configValueWithDefault(descriptor, "bits", 26);  // for lat/long, ~ 1ft
        uassert(16803, "bits in geo index must be between 1 and 32", bits > 0 && bits <= 32);

        GeoHashConverter::Parameters params;
        params.bits = static_cast<unsigned>(bits);
        params.max = configValueWithDefault(descriptor, "max", 180.0);
        params.min = configValueWithDefault(descriptor, "min", -180.0);
        double numBuckets = (1024 * 1024 * 1024 * 4.0);
        params.scaling = numBuckets / (params.max - params.min);

        _params.geoHashConverter.reset(new GeoHashConverter(params));

        BSONObjBuilder b;
        b.appendNull("");
        _nullObj = b.obj();
        _nullElt = _nullObj.firstElement();
    }
Beispiel #16
0
static void bson2bamboo(const dclass::DistributedType *type,
                        const BSONElement &element,
                        Datagram &dg)
{
    switch(type->get_type()) {
    case dclass::Type::T_INT8: {
        dg.add_int8(element.Int());
    }
    break;
    case dclass::Type::T_INT16: {
        dg.add_int16(element.Int());
    }
    break;
    case dclass::Type::T_INT32: {
        dg.add_int32(element.Int());
    }
    break;
    case dclass::Type::T_INT64: {
        dg.add_int64(element.Int());
    }
    break;
    case dclass::Type::T_UINT8: {
        dg.add_uint8(element.Int());
    }
    break;
    case dclass::Type::T_UINT16: {
        dg.add_uint16(element.Int());
    }
    break;
    case dclass::Type::T_UINT32: {
        dg.add_uint32(element.Int());
    }
    break;
    case dclass::Type::T_UINT64: {
        dg.add_uint64(element.Int());
    }
    break;
    case dclass::Type::T_CHAR: {
        string str = element.String();
        if(str.size() != 1) {
            throw mongo::DBException("Expected single-length string for char field", 0);
        }
        dg.add_uint8(str[0]);
    }
    break;
    case dclass::Type::T_FLOAT32: {
        dg.add_float32(element.Number());
    }
    break;
    case dclass::Type::T_FLOAT64: {
        dg.add_float64(element.Number());
    }
    break;
    case dclass::Type::T_STRING: {
        dg.add_data(element.String());
    }
    break;
    case dclass::Type::T_VARSTRING: {
        dg.add_string(element.String());
    }
    break;
    case dclass::Type::T_BLOB: {
        int len;
        const uint8_t *rawdata = (const uint8_t *)element.binData(len);
        dg.add_data(rawdata, len);
    }
    break;
    case dclass::Type::T_VARBLOB: {
        int len;
        const uint8_t *rawdata = (const uint8_t *)element.binData(len);
        dg.add_blob(rawdata, len);
    }
    break;
    case dclass::Type::T_ARRAY: {
        const dclass::ArrayType *array = type->as_array();
        std::vector<BSONElement> data = element.Array();

        for(auto it = data.begin(); it != data.end(); ++it) {
            bson2bamboo(array->get_element_type(), *it, dg);
        }
    }
    break;
    case dclass::Type::T_VARARRAY: {
        const dclass::ArrayType *array = type->as_array();
        std::vector<BSONElement> data = element.Array();

        DatagramPtr newdg = Datagram::create();

        for(auto it = data.begin(); it != data.end(); ++it) {
            bson2bamboo(array->get_element_type(), *it, *newdg);
        }

        dg.add_blob(newdg->get_data(), newdg->size());
    }
    break;
    case dclass::Type::T_STRUCT: {
        const dclass::Struct *s = type->as_struct();
        size_t fields = s->get_num_fields();
        for(unsigned int i = 0; i < fields; ++i) {
            const dclass::Field *field = s->get_field(i);
            bson2bamboo(field->get_type(), element[field->get_name()], dg);
        }
    }
    break;
    case dclass::Type::T_METHOD: {
        const dclass::Method *m = type->as_method();
        size_t parameters = m->get_num_parameters();
        for(unsigned int i = 0; i < parameters; ++i) {
            const dclass::Parameter *parameter = m->get_parameter(i);
            string name = parameter->get_name();
            if(name.empty() || element[name].eoo()) {
                stringstream n;
                n << "_" << i;
                name = n.str();
            }
            bson2bamboo(parameter->get_type(), element[name], dg);
        }
    }
    break;
    case dclass::Type::T_INVALID:
    default:
        assert(false);
        break;
    }
}
Beispiel #17
0
    Status GeoNearExpression::parseNewQuery(const BSONObj &obj) {
        bool hasGeometry = false;

        BSONObjIterator objIt(obj);
        if (!objIt.more()) {
            return Status(ErrorCodes::BadValue, "empty geo near query object");
        }
        BSONElement e = objIt.next();
        // Just one arg. to $geoNear.
        if (objIt.more()) {
            return Status(ErrorCodes::BadValue, mongoutils::str::stream() <<
                          "geo near accepts just one argument when querying for a GeoJSON " <<
                          "point. Extra field found: " << objIt.next());
        }

        // Parse "new" near:
        // t.find({"geo" : {"$near" : {"$geometry": pointA, $minDistance: 1, $maxDistance: 3}}})
        // t.find({"geo" : {"$geoNear" : {"$geometry": pointA, $minDistance: 1, $maxDistance: 3}}})
        if (!e.isABSONObj()) {
            return Status(ErrorCodes::BadValue, "geo near query argument is not an object");
        }
        BSONObj::MatchType matchType = static_cast<BSONObj::MatchType>(e.getGtLtOp());
        if (BSONObj::opNEAR != matchType) {
            return Status(ErrorCodes::BadValue, mongoutils::str::stream() <<
                          "invalid geo near query operator: " << e.fieldName());
        }

        // Iterate over the argument.
        BSONObjIterator it(e.embeddedObject());
        while (it.more()) {
            BSONElement e = it.next();
            if (equals(e.fieldName(), "$geometry")) {
                if (e.isABSONObj()) {
                    BSONObj embeddedObj = e.embeddedObject();
                    Status status = GeoParser::parseQueryPoint(e, centroid.get());
                    if (!status.isOK()) {
                        return Status(ErrorCodes::BadValue,
                                      str::stream()
                                              << "invalid point in geo near query $geometry argument: "
                                              << embeddedObj << "  " << status.reason());
                    }
                    uassert(16681, "$near requires geojson point, given " + embeddedObj.toString(),
                            (SPHERE == centroid->crs));
                    hasGeometry = true;
                }
            } else if (equals(e.fieldName(), "$minDistance")) {
                uassert(16897, "$minDistance must be a number", e.isNumber());
                minDistance = e.Number();
                uassert(16898, "$minDistance must be non-negative", minDistance >= 0.0);
            } else if (equals(e.fieldName(), "$maxDistance")) {
                uassert(16899, "$maxDistance must be a number", e.isNumber());
                maxDistance = e.Number();
                uassert(16900, "$maxDistance must be non-negative", maxDistance >= 0.0);
            }
        }

        if (!hasGeometry) {
            return Status(ErrorCodes::BadValue, "$geometry is required for geo near query");
        }

        return Status::OK();
    }