예제 #1
0
    TEST(ExpressionGeoTest, GeoNear1) {
        BSONObj query = fromjson("{loc:{$near:{$maxDistance:100, "
                                 "$geometry:{type:\"Point\", coordinates:[0,0]}}}}");
        NearQuery nq;
        ASSERT_OK(nq.parseFrom(query["loc"].Obj()));

        GeoNearMatchExpression gne;
        ASSERT(gne.init("a", nq, query).isOK());

        // We can't match the data but we can make sure it was parsed OK.
        ASSERT_EQUALS(gne.getData().centroid.crs, SPHERE);
        ASSERT_EQUALS(gne.getData().minDistance, 0);
        ASSERT_EQUALS(gne.getData().maxDistance, 100);
    }
    Status S2IndexCursor::seek(const BSONObj &position) {
        vector<GeoQuery> regions;
        bool isNearQuery = false;
        NearQuery nearQuery;

        // Go through the fields that we index, and for each geo one, make
        // a GeoQuery object for the S2*Cursor class to do intersection
        // testing/cover generating with.
        BSONObjIterator keyIt(_descriptor->keyPattern());
        while (keyIt.more()) {
            BSONElement keyElt = keyIt.next();

            if (keyElt.type() != String || IndexNames::GEO_2DSPHERE != keyElt.valuestr()) {
                continue;
            }

            BSONElement e = position.getFieldDotted(keyElt.fieldName());
            if (e.eoo()) { continue; }
            if (!e.isABSONObj()) { continue; }
            BSONObj obj = e.Obj();

            if (nearQuery.parseFrom(obj, _params.radius)) {
                if (isNearQuery) {
                    return Status(ErrorCodes::BadValue, "Only one $near clause allowed: " +
                                  position.toString(), 16685);
                }
                isNearQuery = true;
                nearQuery.field = keyElt.fieldName();
                continue;
            }

            GeoQuery geoQueryField(keyElt.fieldName());
            if (!geoQueryField.parseFrom(obj)) {
                return Status(ErrorCodes::BadValue, "can't parse query (2dsphere): "
                                                   + obj.toString(), 16535);
            }
            if (!geoQueryField.hasS2Region()) {
                return Status(ErrorCodes::BadValue, "Geometry unsupported: " + obj.toString(),
                              16684);
            }
            regions.push_back(geoQueryField);
        }

        // Remove all the indexed geo regions from the query.  The s2*cursor will
        // instead create a covering for that key to speed up the search.
        //
        // One thing to note is that we create coverings for indexed geo keys during
        // a near search to speed it up further.
        BSONObjBuilder geoFieldsToNuke;

        if (isNearQuery) {
            geoFieldsToNuke.append(nearQuery.field, "");
        }

        for (size_t i = 0; i < regions.size(); ++i) {
            geoFieldsToNuke.append(regions[i].getField(), "");
        }

        // false means we want to filter OUT geoFieldsToNuke, not filter to include only that.
        BSONObj filteredQuery = position.filterFieldsUndotted(geoFieldsToNuke.obj(), false);

        if (isNearQuery) {
            S2NearIndexCursor* nearCursor = new S2NearIndexCursor(_descriptor, _params);
            _underlyingCursor.reset(nearCursor);
            nearCursor->seek(filteredQuery, nearQuery, regions);
        } else {
            S2SimpleCursor* simpleCursor = new S2SimpleCursor(_descriptor, _params);
            _underlyingCursor.reset(simpleCursor);
            simpleCursor->seek(filteredQuery, regions);
        }

        return Status::OK();
    }