summaryrefslogtreecommitdiff
path: root/db/geo/2d.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'db/geo/2d.cpp')
-rw-r--r--db/geo/2d.cpp710
1 files changed, 362 insertions, 348 deletions
diff --git a/db/geo/2d.cpp b/db/geo/2d.cpp
index 6e9aac7c6ba..3102b8a3469 100644
--- a/db/geo/2d.cpp
+++ b/db/geo/2d.cpp
@@ -34,7 +34,7 @@ namespace mongo {
#if 0
# define GEODEBUG(x) cout << x << endl;
# define GEODEBUGPRINT(x) PRINT(x)
- inline void PREFIXDEBUG(GeoHash prefix, const GeoConvert* g){
+ inline void PREFIXDEBUG(GeoHash prefix, const GeoConvert* g) {
if (!prefix.constrains()) {
cout << "\t empty prefix" << endl;
return ;
@@ -47,14 +47,14 @@ namespace mongo {
Point center ( (ll._x+tr._x)/2, (ll._y+tr._y)/2 );
double radius = fabs(ll._x - tr._x) / 2;
- cout << "\t ll: " << ll.toString() << " tr: " << tr.toString()
+ cout << "\t ll: " << ll.toString() << " tr: " << tr.toString()
<< " center: " << center.toString() << " radius: " << radius << endl;
}
#else
-# define GEODEBUG(x)
-# define GEODEBUGPRINT(x)
-# define PREFIXDEBUG(x, y)
+# define GEODEBUG(x)
+# define GEODEBUGPRINT(x)
+# define PREFIXDEBUG(x, y)
#endif
const double EARTH_RADIUS_KM = 6371;
@@ -65,9 +65,9 @@ namespace mongo {
GEO_SPHERE
};
- inline double computeXScanDistance(double y, double maxDistDegrees){
+ inline double computeXScanDistance(double y, double maxDistDegrees) {
// TODO: this overestimates for large madDistDegrees far from the equator
- return maxDistDegrees / min(cos(deg2rad(min(+89.0, y + maxDistDegrees))),
+ return maxDistDegrees / min(cos(deg2rad(min(+89.0, y + maxDistDegrees))),
cos(deg2rad(max(-89.0, y - maxDistDegrees))));
}
@@ -78,14 +78,14 @@ namespace mongo {
class Geo2dType : public IndexType , public GeoConvert {
public:
Geo2dType( const IndexPlugin * plugin , const IndexSpec* spec )
- : IndexType( plugin , spec ){
-
+ : IndexType( plugin , spec ) {
+
BSONObjBuilder orderBuilder;
BSONObjIterator i( spec->keyPattern );
- while ( i.more() ){
+ while ( i.more() ) {
BSONElement e = i.next();
- if ( e.type() == String && GEO2DNAME == e.valuestr() ){
+ if ( e.type() == String && GEO2DNAME == e.valuestr() ) {
uassert( 13022 , "can't have 2 geo field" , _geo.size() == 0 );
uassert( 13023 , "2d has to be first in index" , _other.size() == 0 );
_geo = e.fieldName();
@@ -95,16 +95,16 @@ namespace mongo {
}
orderBuilder.append( "" , 1 );
}
-
+
uassert( 13024 , "no geo field specified" , _geo.size() );
-
+
_bits = _configval( spec , "bits" , 26 ); // for lat/long, ~ 1ft
uassert( 13028 , "can't have more than 32 bits in geo index" , _bits <= 32 );
_max = _configval( spec , "max" , 180 );
_min = _configval( spec , "min" , -180 );
-
+
_scaling = (1024*1024*1024*4.0)/(_max-_min);
_order = orderBuilder.obj();
@@ -115,30 +115,30 @@ namespace mongo {
_error = distance(a, b);
}
- int _configval( const IndexSpec* spec , const string& name , int def ){
+ int _configval( const IndexSpec* spec , const string& name , int def ) {
BSONElement e = spec->info[name];
if ( e.isNumber() )
return e.numberInt();
return def;
}
- ~Geo2dType(){
-
+ ~Geo2dType() {
+
}
- virtual BSONObj fixKey( const BSONObj& in ) {
+ virtual BSONObj fixKey( const BSONObj& in ) {
if ( in.firstElement().type() == BinData )
return in;
BSONObjBuilder b(in.objsize()+16);
-
+
if ( in.firstElement().isABSONObj() )
_hash( in.firstElement().embeddedObject() ).append( b , "" );
else if ( in.firstElement().type() == String )
GeoHash( in.firstElement().valuestr() ).append( b , "" );
else if ( in.firstElement().type() == RegEx )
GeoHash( in.firstElement().regex() ).append( b , "" );
- else
+ else
return in;
BSONObjIterator i(in);
@@ -164,7 +164,7 @@ namespace mongo {
_hash( embed ).append( b , "" );
- for ( size_t i=0; i<_other.size(); i++ ){
+ for ( size_t i=0; i<_other.size(); i++ ) {
BSONElement e = obj.getFieldDotted(_other[i]);
if ( e.eoo() )
e = _spec->missingField();
@@ -172,11 +172,11 @@ namespace mongo {
}
keys.insert( b.obj() );
}
-
+
GeoHash _tohash( const BSONElement& e ) const {
if ( e.isABSONObj() )
return _hash( e.embeddedObject() );
-
+
return GeoHash( e , _bits );
}
@@ -186,7 +186,7 @@ namespace mongo {
BSONElement x = i.next();
uassert( 13068 , "geo field only has 1 element" , i.more() );
BSONElement y = i.next();
-
+
uassert( 13026 , "geo values have to be numbers: " + o.toString() , x.isNumber() && y.isNumber() );
return hash( x.number() , y.number() );
@@ -204,33 +204,33 @@ namespace mongo {
b.append( "y" , _unconvert( y ) );
return b.obj();
}
-
+
unsigned _convert( double in ) const {
uassert( 13027 , "point not in range" , in <= (_max + _error) && in >= (_min - _error) );
in -= _min;
assert( in > 0 );
return (unsigned)(in * _scaling);
}
-
+
double _unconvert( unsigned in ) const {
double x = in;
x /= _scaling;
x += _min;
return x;
}
-
+
void unhash( const GeoHash& h , double& x , double& y ) const {
unsigned a,b;
h.unhash(a,b);
x = _unconvert( a );
y = _unconvert( b );
}
-
+
double distance( const GeoHash& a , const GeoHash& b ) const {
double ax,ay,bx,by;
unhash( a , ax , ay );
unhash( b , bx , by );
-
+
double dx = bx - ax;
double dy = by - ay;
@@ -265,10 +265,10 @@ namespace mongo {
virtual IndexSuitability suitability( const BSONObj& query , const BSONObj& order ) const {
BSONElement e = query.getFieldDotted(_geo.c_str());
- switch ( e.type() ){
+ switch ( e.type() ) {
case Object: {
BSONObj sub = e.embeddedObject();
- switch ( sub.firstElement().getGtLtOp() ){
+ switch ( sub.firstElement().getGtLtOp() ) {
case BSONObj::opNEAR:
case BSONObj::opWITHIN:
return OPTIMAL;
@@ -284,7 +284,7 @@ namespace mongo {
string _geo;
vector<string> _other;
-
+
unsigned _bits;
int _max;
int _min;
@@ -296,38 +296,38 @@ namespace mongo {
class Box {
public:
-
+
Box( const Geo2dType * g , const GeoHash& hash )
- : _min( g , hash ) ,
- _max( _min._x + g->sizeEdge( hash ) , _min._y + g->sizeEdge( hash ) ){
+ : _min( g , hash ) ,
+ _max( _min._x + g->sizeEdge( hash ) , _min._y + g->sizeEdge( hash ) ) {
}
-
+
Box( double x , double y , double size )
- : _min( x , y ) ,
- _max( x + size , y + size ){
+ : _min( x , y ) ,
+ _max( x + size , y + size ) {
}
Box( Point min , Point max )
- : _min( min ) , _max( max ){
+ : _min( min ) , _max( max ) {
}
- Box(){}
+ Box() {}
string toString() const {
StringBuilder buf(64);
buf << _min.toString() << " -->> " << _max.toString();
return buf.str();
}
-
+
bool between( double min , double max , double val , double fudge=0) const {
return val + fudge >= min && val <= max + fudge;
}
-
+
bool mid( double amin , double amax , double bmin , double bmax , bool min , double& res ) const {
assert( amin <= amax );
assert( bmin <= bmax );
- if ( amin < bmin ){
+ if ( amin < bmin ) {
if ( amax < bmin )
return false;
res = min ? bmin : amax;
@@ -340,16 +340,16 @@ namespace mongo {
}
double intersects( const Box& other ) const {
-
+
Point boundMin(0,0);
Point boundMax(0,0);
-
+
if ( mid( _min._x , _max._x , other._min._x , other._max._x , true , boundMin._x ) == false ||
- mid( _min._x , _max._x , other._min._x , other._max._x , false , boundMax._x ) == false ||
- mid( _min._y , _max._y , other._min._y , other._max._y , true , boundMin._y ) == false ||
- mid( _min._y , _max._y , other._min._y , other._max._y , false , boundMax._y ) == false )
+ mid( _min._x , _max._x , other._min._x , other._max._x , false , boundMax._x ) == false ||
+ mid( _min._y , _max._y , other._min._y , other._max._y , true , boundMin._y ) == false ||
+ mid( _min._y , _max._y , other._min._y , other._max._y , false , boundMax._y ) == false )
return 0;
-
+
Box intersection( boundMin , boundMax );
return intersection.area() / ( ( area() + other.area() ) / 2 );
@@ -364,49 +364,49 @@ namespace mongo {
( _min._y + _max._y ) / 2 );
}
- bool inside( Point p , double fudge = 0 ){
+ bool inside( Point p , double fudge = 0 ) {
bool res = inside( p._x , p._y , fudge );
//cout << "is : " << p.toString() << " in " << toString() << " = " << res << endl;
return res;
}
-
- bool inside( double x , double y , double fudge = 0 ){
- return
+
+ bool inside( double x , double y , double fudge = 0 ) {
+ return
between( _min._x , _max._x , x , fudge ) &&
between( _min._y , _max._y , y , fudge );
}
- bool contains(const Box& other, double fudge=0){
+ bool contains(const Box& other, double fudge=0) {
return inside(other._min, fudge) && inside(other._max, fudge);
}
-
+
Point _min;
Point _max;
};
-
+
class Geo2dPlugin : public IndexPlugin {
public:
- Geo2dPlugin() : IndexPlugin( GEO2DNAME ){
+ Geo2dPlugin() : IndexPlugin( GEO2DNAME ) {
}
-
+
virtual IndexType* generate( const IndexSpec* spec ) const {
return new Geo2dType( this , spec );
}
} geo2dplugin;
-
+
struct GeoUnitTest : public UnitTest {
-
- int round( double d ){
+
+ int round( double d ) {
return (int)(.5+(d*1000));
}
-
+
#define GEOHEQ(a,b) if ( a.toString() != b ){ cout << "[" << a.toString() << "] != [" << b << "]" << endl; assert( a == GeoHash(b) ); }
- void run(){
+ void run() {
assert( ! GeoHash::isBitSet( 0 , 0 ) );
assert( ! GeoHash::isBitSet( 0 , 31 ) );
assert( GeoHash::isBitSet( 1 , 31 ) );
-
+
IndexSpec i( BSON( "loc" << "2d" ) );
Geo2dType g( &geo2dplugin , &i );
{
@@ -432,7 +432,7 @@ namespace mongo {
assert( round( in["x"].number() ) == round( out["x"].number() ) );
assert( round( in["y"].number() ) == round( out["y"].number() ) );
}
-
+
{
GeoHash h( "0000" );
h.move( 0 , 1 );
@@ -445,13 +445,13 @@ namespace mongo {
GEOHEQ( h , "0100" );
h.move( 0 , -1 );
GEOHEQ( h , "0001" );
-
+
h.init( "0000" );
h.move( 1 , 0 );
GEOHEQ( h , "0010" );
}
-
+
{
Box b( 5 , 5 , 2 );
assert( "(5,5) -->> (7,7)" == b.toString() );
@@ -465,7 +465,7 @@ namespace mongo {
b = g.hash( 42 , 44 );
assert( round(10) == round(g.distance( a , b )) );
}
-
+
{
GeoHash x("0000");
assert( 0 == x.getHash() );
@@ -475,7 +475,7 @@ namespace mongo {
assert( GeoHash( "1100").hasPrefix( GeoHash( "11" ) ) );
assert( ! GeoHash( "1000").hasPrefix( GeoHash( "11" ) ) );
}
-
+
{
GeoHash x("1010");
GEOHEQ( x , "1010" );
@@ -483,8 +483,8 @@ namespace mongo {
GEOHEQ( y , "101001" );
}
- {
-
+ {
+
GeoHash a = g.hash( 5 , 5 );
GeoHash b = g.hash( 5 , 7 );
GeoHash c = g.hash( 100 , 100 );
@@ -530,13 +530,13 @@ namespace mongo {
assert( entry.hasPrefix( GeoHash( "1100" ) ) );
assert( entry.hasPrefix( prefix ) );
}
-
+
{
GeoHash a = g.hash( 50 , 50 );
GeoHash b = g.hash( 48 , 54 );
assert( round( 4.47214 ) == round( g.distance( a , b ) ) );
}
-
+
{
Box b( Point( 29.762283 , -95.364271 ) , Point( 29.764283000000002 , -95.36227099999999 ) );
@@ -555,7 +555,7 @@ namespace mongo {
int N = 10000;
{
Timer t;
- for ( int i=0; i<N; i++ ){
+ for ( int i=0; i<N; i++ ) {
unsigned x = (unsigned)rand();
unsigned y = (unsigned)rand();
GeoHash h( x , y );
@@ -569,7 +569,7 @@ namespace mongo {
{
Timer t;
- for ( int i=0; i<N; i++ ){
+ for ( int i=0; i<N; i++ ) {
unsigned x = (unsigned)rand();
unsigned y = (unsigned)rand();
GeoHash h( x , y );
@@ -600,7 +600,7 @@ namespace mongo {
{
Point BNA (-1.5127, 0.6304);
Point LAX (-2.0665, 0.5924);
-
+
double dist1 = spheredist_rad(BNA, LAX);
double dist2 = spheredist_rad(LAX, BNA);
@@ -611,7 +611,7 @@ namespace mongo {
{
Point JFK (-73.77694444, 40.63861111 );
Point LAX (-118.40, 33.94);
-
+
double dist = spheredist_deg(JFK, LAX) * EARTH_RADIUS_MILES;
assert( dist > 2469 && dist < 2470 );
}
@@ -635,18 +635,18 @@ namespace mongo {
}
}
} geoUnitTest;
-
+
class GeoPoint {
public:
- GeoPoint(){
+ GeoPoint() {
}
GeoPoint( const KeyNode& node , double distance )
- : _key( node.key ) , _loc( node.recordLoc ) , _o( node.recordLoc.obj() ) , _distance( distance ){
+ : _key( node.key ) , _loc( node.recordLoc ) , _o( node.recordLoc.obj() ) , _distance( distance ) {
}
GeoPoint( const BSONObj& key , DiskLoc loc , double distance )
- : _key(key) , _loc(loc) , _o( loc.obj() ) , _distance( distance ){
+ : _key(key) , _loc(loc) , _o( loc.obj() ) , _distance( distance ) {
}
bool operator<( const GeoPoint& other ) const {
@@ -667,44 +667,44 @@ namespace mongo {
public:
GeoAccumulator( const Geo2dType * g , const BSONObj& filter )
: _g(g) , _lookedAt(0) , _objectsLoaded(0) , _found(0) {
- if ( ! filter.isEmpty() ){
+ if ( ! filter.isEmpty() ) {
_matcher.reset( new CoveredIndexMatcher( filter , g->keyPattern() ) );
}
}
- virtual ~GeoAccumulator(){
+ virtual ~GeoAccumulator() {
}
- virtual void add( const KeyNode& node ){
+ virtual void add( const KeyNode& node ) {
// when looking at other boxes, don't want to look at some object twice
pair<set<DiskLoc>::iterator,bool> seenBefore = _seen.insert( node.recordLoc );
- if ( ! seenBefore.second ){
+ if ( ! seenBefore.second ) {
GEODEBUG( "\t\t\t\t already seen : " << node.recordLoc.obj()["_id"] );
return;
}
_lookedAt++;
-
+
// distance check
double d = 0;
- if ( ! checkDistance( GeoHash( node.key.firstElement() ) , d ) ){
+ if ( ! checkDistance( GeoHash( node.key.firstElement() ) , d ) ) {
GEODEBUG( "\t\t\t\t bad distance : " << node.recordLoc.obj() << "\t" << d );
return;
- }
+ }
GEODEBUG( "\t\t\t\t good distance : " << node.recordLoc.obj() << "\t" << d );
-
+
// matcher
MatchDetails details;
- if ( _matcher.get() ){
+ if ( _matcher.get() ) {
bool good = _matcher->matches( node.key , node.recordLoc , &details );
if ( details.loadedObject )
_objectsLoaded++;
-
- if ( ! good ){
+
+ if ( ! good ) {
GEODEBUG( "\t\t\t\t didn't match : " << node.recordLoc.obj()["_id"] );
return;
}
}
-
+
if ( ! details.loadedObject ) // dont double count
_objectsLoaded++;
@@ -718,7 +718,7 @@ namespace mongo {
long long found() const {
return _found;
}
-
+
const Geo2dType * _g;
set<DiskLoc> _seen;
auto_ptr<CoveredIndexMatcher> _matcher;
@@ -727,7 +727,7 @@ namespace mongo {
long long _objectsLoaded;
long long _found;
};
-
+
class GeoHopper : public GeoAccumulator {
public:
typedef multiset<GeoPoint> Holder;
@@ -736,33 +736,34 @@ namespace mongo {
: GeoAccumulator( g , filter ) , _max( max ) , _near( n ), _maxDistance( maxDistance ), _type( type ), _farthest(-1)
{}
- virtual bool checkDistance( const GeoHash& h , double& d ){
- switch (_type){
- case GEO_PLAIN:
- d = _near.distance( Point(_g, h) );
- break;
- case GEO_SPHERE:
- d = spheredist_deg(_near, Point(_g, h));
- break;
- default:
- assert(0);
+ virtual bool checkDistance( const GeoHash& h , double& d ) {
+ switch (_type) {
+ case GEO_PLAIN:
+ d = _near.distance( Point(_g, h) );
+ break;
+ case GEO_SPHERE:
+ d = spheredist_deg(_near, Point(_g, h));
+ break;
+ default:
+ assert(0);
}
bool good = d < _maxDistance && ( _points.size() < _max || d < farthest() );
- GEODEBUG( "\t\t\t\t\t\t\t checkDistance " << _near.toString() << "\t" << h << "\t" << d
+ GEODEBUG( "\t\t\t\t\t\t\t checkDistance " << _near.toString() << "\t" << h << "\t" << d
<< " ok: " << good << " farthest: " << farthest() );
return good;
}
-
- virtual void addSpecific( const KeyNode& node , double d ){
+
+ virtual void addSpecific( const KeyNode& node , double d ) {
GEODEBUG( "\t\t" << GeoHash( node.key.firstElement() ) << "\t" << node.recordLoc.obj() << "\t" << d );
_points.insert( GeoPoint( node.key , node.recordLoc , d ) );
- if ( _points.size() > _max ){
+ if ( _points.size() > _max ) {
_points.erase( --_points.end() );
-
+
Holder::iterator i = _points.end();
i--;
_farthest = i->_distance;
- } else {
+ }
+ else {
if (d > _farthest)
_farthest = d;
}
@@ -780,42 +781,42 @@ namespace mongo {
GeoDistType _type;
double _farthest;
};
-
+
struct BtreeLocation {
int pos;
bool found;
DiskLoc bucket;
-
- BSONObj key(){
+
+ BSONObj key() {
if ( bucket.isNull() )
return BSONObj();
return bucket.btree()->keyNode( pos ).key;
}
-
- bool hasPrefix( const GeoHash& hash ){
+
+ bool hasPrefix( const GeoHash& hash ) {
BSONElement e = key().firstElement();
if ( e.eoo() )
return false;
return GeoHash( e ).hasPrefix( hash );
}
-
- bool advance( int direction , int& totalFound , GeoAccumulator* all ){
+
+ bool advance( int direction , int& totalFound , GeoAccumulator* all ) {
if ( bucket.isNull() )
return false;
bucket = bucket.btree()->advance( bucket , pos , direction , "btreelocation" );
-
+
if ( all )
return checkCur( totalFound , all );
-
+
return ! bucket.isNull();
}
- bool checkCur( int& totalFound , GeoAccumulator* all ){
+ bool checkCur( int& totalFound , GeoAccumulator* all ) {
if ( bucket.isNull() )
return false;
- if ( bucket.btree()->isUsed(pos) ){
+ if ( bucket.btree()->isUsed(pos) ) {
totalFound++;
all->add( bucket.btree()->keyNode( pos ) );
}
@@ -826,31 +827,30 @@ namespace mongo {
return true;
}
- string toString(){
+ string toString() {
stringstream ss;
ss << "bucket: " << bucket.toString() << " pos: " << pos << " found: " << found;
return ss.str();
}
- static bool initial( const IndexDetails& id , const Geo2dType * spec ,
- BtreeLocation& min , BtreeLocation& max ,
+ static bool initial( const IndexDetails& id , const Geo2dType * spec ,
+ BtreeLocation& min , BtreeLocation& max ,
GeoHash start ,
- int & found , GeoAccumulator * hopper )
- {
-
+ int & found , GeoAccumulator * hopper ) {
+
Ordering ordering = Ordering::make(spec->_order);
- min.bucket = id.head.btree()->locate( id , id.head , start.wrap() ,
+ min.bucket = id.head.btree()->locate( id , id.head , start.wrap() ,
ordering , min.pos , min.found , minDiskLoc );
if (hopper) min.checkCur( found , hopper );
max = min;
-
- if ( min.bucket.isNull() || ( hopper && !(hopper->found()) ) ){
- min.bucket = id.head.btree()->locate( id , id.head , start.wrap() ,
+
+ if ( min.bucket.isNull() || ( hopper && !(hopper->found()) ) ) {
+ min.bucket = id.head.btree()->locate( id , id.head , start.wrap() ,
ordering , min.pos , min.found , minDiskLoc , -1 );
if (hopper) min.checkCur( found , hopper );
}
-
+
return ! min.bucket.isNull() || ! max.bucket.isNull();
}
};
@@ -860,29 +860,31 @@ namespace mongo {
GeoSearch( const Geo2dType * g , const GeoHash& n , int numWanted=100 , BSONObj filter=BSONObj() , double maxDistance = numeric_limits<double>::max() , GeoDistType type=GEO_PLAIN)
: _spec( g ) ,_startPt(g,n), _start( n ) ,
_numWanted( numWanted ) , _filter( filter ) , _maxDistance( maxDistance ) ,
- _hopper( new GeoHopper( g , numWanted , _startPt , filter , maxDistance, type ) ), _type(type)
- {
+ _hopper( new GeoHopper( g , numWanted , _startPt , filter , maxDistance, type ) ), _type(type) {
assert( g->getDetails() );
_nscanned = 0;
_found = 0;
-
- if (type == GEO_PLAIN){
+
+ if (type == GEO_PLAIN) {
_scanDistance = maxDistance;
- } else if (type == GEO_SPHERE) {
- if (maxDistance == numeric_limits<double>::max()){
+ }
+ else if (type == GEO_SPHERE) {
+ if (maxDistance == numeric_limits<double>::max()) {
_scanDistance = maxDistance;
- } else {
+ }
+ else {
//TODO: consider splitting into x and y scan distances
_scanDistance = computeXScanDistance(_startPt._y, rad2deg(maxDistance));
}
- } else {
+ }
+ else {
assert(0);
}
}
-
- void exec(){
+
+ void exec() {
const IndexDetails& id = *_spec->getDetails();
-
+
const BtreeBucket * head = id.head.btree();
assert( head );
/*
@@ -892,20 +894,20 @@ namespace mongo {
* 3) find optimal set of boxes that complete circle
* 4) use regular btree cursors to scan those boxes
*/
-
+
GeoHopper * hopper = _hopper.get();
_prefix = _start;
BtreeLocation min,max;
- { // 1 regular geo hash algorithm
-
+ {
+ // 1 regular geo hash algorithm
+
if ( ! BtreeLocation::initial( id , _spec , min , max , _start , _found , NULL ) )
return;
-
+
while ( !_prefix.constrains() || // if next pass would cover universe, just keep going
- ( _hopper->found() < _numWanted && _spec->sizeEdge( _prefix ) <= _scanDistance))
- {
+ ( _hopper->found() < _numWanted && _spec->sizeEdge( _prefix ) <= _scanDistance)) {
GEODEBUG( _prefix << "\t" << _found << "\t DESC" );
while ( min.hasPrefix(_prefix) && min.checkCur(_found, hopper) && min.advance(-1, _found, NULL) )
_nscanned++;
@@ -913,7 +915,7 @@ namespace mongo {
while ( max.hasPrefix(_prefix) && max.checkCur(_found, hopper) && max.advance(+1, _found, NULL) )
_nscanned++;
- if ( ! _prefix.constrains() ){
+ if ( ! _prefix.constrains() ) {
GEODEBUG( "done search w/o part 2" )
return;
}
@@ -927,10 +929,11 @@ namespace mongo {
// 2
double farthest = hopper->farthest();
GEODEBUGPRINT(hopper->farthest());
- if (farthest == -1){
+ if (farthest == -1) {
// Nothing found in Phase 1
farthest = _scanDistance;
- } else if (_type == GEO_SPHERE) {
+ }
+ else if (_type == GEO_SPHERE) {
farthest = std::min(_scanDistance, computeXScanDistance(_startPt._y, rad2deg(farthest)));
}
GEODEBUGPRINT(farthest);
@@ -939,13 +942,13 @@ namespace mongo {
GEODEBUGPRINT(want.toString());
_prefix = _start;
- while (_prefix.constrains() && _spec->sizeEdge( _prefix ) < farthest ){
+ while (_prefix.constrains() && _spec->sizeEdge( _prefix ) < farthest ) {
_prefix = _prefix.up();
}
PREFIXDEBUG(_prefix, _spec);
- if (_prefix.getBits() <= 1){
+ if (_prefix.getBits() <= 1) {
// TODO consider walking in $natural order
while ( min.checkCur(_found, hopper) && min.advance(-1, _found, NULL) )
@@ -954,16 +957,16 @@ namespace mongo {
_nscanned++;
GEODEBUG( "done search after scanning whole collection" )
- return;
+ return;
}
- if ( logLevel > 0 ){
- log(1) << "want: " << want << " found:" << _found << " nscanned: " << _nscanned << " hash size:" << _spec->sizeEdge( _prefix )
+ if ( logLevel > 0 ) {
+ log(1) << "want: " << want << " found:" << _found << " nscanned: " << _nscanned << " hash size:" << _spec->sizeEdge( _prefix )
<< " farthest: " << farthest << " using box: " << Box( _spec , _prefix ).toString() << endl;
}
- for ( int x=-1; x<=1; x++ ){
- for ( int y=-1; y<=1; y++ ){
+ for ( int x=-1; x<=1; x++ ) {
+ for ( int y=-1; y<=1; y++ ) {
GeoHash toscan = _prefix;
toscan.move( x , y );
@@ -973,51 +976,52 @@ namespace mongo {
}
}
GEODEBUG( "done search" )
-
+
}
- void doBox( const IndexDetails& id , const Box& want , const GeoHash& toscan , int depth = 0 ){
+ void doBox( const IndexDetails& id , const Box& want , const GeoHash& toscan , int depth = 0 ) {
Box testBox( _spec , toscan );
- if ( logLevel > 2 ){
+ if ( logLevel > 2 ) {
cout << "\t";
for ( int i=0; i<depth; i++ )
cout << "\t";
cout << " doBox: " << testBox.toString() << "\t" << toscan.toString() << " scanned so far: " << _nscanned << endl;
- } else {
+ }
+ else {
GEODEBUGPRINT(testBox.toString());
}
- if (_alreadyScanned.contains(testBox, _spec->_error)){
+ if (_alreadyScanned.contains(testBox, _spec->_error)) {
GEODEBUG("skipping box: already scanned");
return; // been here, done this
}
double intPer = testBox.intersects( want );
-
- if ( intPer <= 0 ){
+
+ if ( intPer <= 0 ) {
GEODEBUG("skipping box: not in want");
return;
}
-
+
bool goDeeper = intPer < .5 && depth < 2;
long long myscanned = 0;
-
+
BtreeLocation loc;
- loc.bucket = id.head.btree()->locate( id , id.head , toscan.wrap() , Ordering::make(_spec->_order) ,
- loc.pos , loc.found , minDiskLoc );
+ loc.bucket = id.head.btree()->locate( id , id.head , toscan.wrap() , Ordering::make(_spec->_order) ,
+ loc.pos , loc.found , minDiskLoc );
loc.checkCur( _found , _hopper.get() );
- while ( loc.hasPrefix( toscan ) && loc.advance( 1 , _found , _hopper.get() ) ){
+ while ( loc.hasPrefix( toscan ) && loc.advance( 1 , _found , _hopper.get() ) ) {
_nscanned++;
- if ( ++myscanned > 100 && goDeeper ){
+ if ( ++myscanned > 100 && goDeeper ) {
doBox( id , want , toscan + "00" , depth + 1);
doBox( id , want , toscan + "01" , depth + 1);
doBox( id , want , toscan + "10" , depth + 1);
doBox( id , want , toscan + "11" , depth + 1);
- return;
+ return;
}
}
-
+
}
@@ -1042,17 +1046,17 @@ namespace mongo {
class GeoCursorBase : public Cursor {
public:
GeoCursorBase( const Geo2dType * spec )
- : _spec( spec ), _id( _spec->getDetails() ){
+ : _spec( spec ), _id( _spec->getDetails() ) {
}
- virtual DiskLoc refLoc(){ return DiskLoc(); }
+ virtual DiskLoc refLoc() { return DiskLoc(); }
virtual BSONObj indexKeyPattern() {
return _spec->keyPattern();
}
- virtual void noteLocation() {
+ virtual void noteLocation() {
// no-op since these are meant to be safe
}
@@ -1063,12 +1067,12 @@ namespace mongo {
virtual bool supportGetMore() { return false; }
virtual bool supportYields() { return false; }
-
+
virtual bool getsetdup(DiskLoc loc) { return false; }
virtual bool modifiedKeys() const { return true; }
virtual bool isMultiKey() const { return false; }
-
+
const Geo2dType * _spec;
const IndexDetails * _id;
@@ -1077,23 +1081,23 @@ namespace mongo {
class GeoSearchCursor : public GeoCursorBase {
public:
GeoSearchCursor( shared_ptr<GeoSearch> s )
- : GeoCursorBase( s->_spec ) ,
+ : GeoCursorBase( s->_spec ) ,
_s( s ) , _cur( s->_hopper->_points.begin() ) , _end( s->_hopper->_points.end() ), _nscanned() {
- if ( _cur != _end ) {
- ++_nscanned;
- }
+ if ( _cur != _end ) {
+ ++_nscanned;
+ }
}
-
+
virtual ~GeoSearchCursor() {}
-
- virtual bool ok(){
+
+ virtual bool ok() {
return _cur != _end;
}
-
- virtual Record* _current(){ assert(ok()); return _cur->_loc.rec(); }
- virtual BSONObj current(){ assert(ok()); return _cur->_o; }
- virtual DiskLoc currLoc(){ assert(ok()); return _cur->_loc; }
- virtual bool advance(){ _cur++; incNscanned(); return ok(); }
+
+ virtual Record* _current() { assert(ok()); return _cur->_loc.rec(); }
+ virtual BSONObj current() { assert(ok()); return _cur->_o; }
+ virtual DiskLoc currLoc() { assert(ok()); return _cur->_loc; }
+ virtual bool advance() { _cur++; incNscanned(); return ok(); }
virtual BSONObj currKey() const { return _cur->_key; }
virtual string toString() {
@@ -1101,21 +1105,21 @@ namespace mongo {
}
- virtual BSONObj prettyStartKey() const {
- return BSON( _s->_spec->_geo << _s->_prefix.toString() );
+ virtual BSONObj prettyStartKey() const {
+ return BSON( _s->_spec->_geo << _s->_prefix.toString() );
}
- virtual BSONObj prettyEndKey() const {
+ virtual BSONObj prettyEndKey() const {
GeoHash temp = _s->_prefix;
temp.move( 1 , 1 );
- return BSON( _s->_spec->_geo << temp.toString() );
+ return BSON( _s->_spec->_geo << temp.toString() );
}
-
+
virtual long long nscanned() { return _nscanned; }
shared_ptr<GeoSearch> _s;
GeoHopper::Holder::iterator _cur;
GeoHopper::Holder::iterator _end;
-
+
void incNscanned() { if ( ok() ) { ++_nscanned; } }
long long _nscanned;
};
@@ -1126,14 +1130,14 @@ namespace mongo {
: GeoCursorBase( g ) ,GeoAccumulator( g , filter ) ,
_type( type ) , _filter( filter ) , _firstCall(true), _nscanned() {
}
-
+
virtual string toString() {
return (string)"GeoBrowse-" + _type;
}
- virtual bool ok(){
+ virtual bool ok() {
bool first = _firstCall;
- if ( _firstCall ){
+ if ( _firstCall ) {
fillStack();
_firstCall = false;
}
@@ -1144,7 +1148,7 @@ namespace mongo {
return true;
}
- while ( moreToDo() ){
+ while ( moreToDo() ) {
fillStack();
if ( ! _cur.isEmpty() ) {
if ( first ) {
@@ -1153,38 +1157,38 @@ namespace mongo {
return true;
}
}
-
+
return false;
}
-
- virtual bool advance(){
+
+ virtual bool advance() {
_cur._o = BSONObj();
-
- if ( _stack.size() ){
+
+ if ( _stack.size() ) {
_cur = _stack.front();
_stack.pop_front();
++_nscanned;
return true;
}
-
+
if ( ! moreToDo() )
return false;
-
+
while ( _cur.isEmpty() && moreToDo() )
fillStack();
return ! _cur.isEmpty() && ++_nscanned;
}
-
- virtual Record* _current(){ assert(ok()); return _cur._loc.rec(); }
- virtual BSONObj current(){ assert(ok()); return _cur._o; }
- virtual DiskLoc currLoc(){ assert(ok()); return _cur._loc; }
+
+ virtual Record* _current() { assert(ok()); return _cur._loc.rec(); }
+ virtual BSONObj current() { assert(ok()); return _cur._o; }
+ virtual DiskLoc currLoc() { assert(ok()); return _cur._loc; }
virtual BSONObj currKey() const { return _cur._key; }
virtual bool moreToDo() = 0;
virtual void fillStack() = 0;
- virtual void addSpecific( const KeyNode& node , double d ){
+ virtual void addSpecific( const KeyNode& node , double d ) {
if ( _cur.isEmpty() )
_cur = GeoPoint( node , d );
else
@@ -1196,31 +1200,31 @@ namespace mongo {
ok();
}
return _nscanned;
- }
-
+ }
+
string _type;
BSONObj _filter;
list<GeoPoint> _stack;
GeoPoint _cur;
bool _firstCall;
-
+
long long _nscanned;
};
class GeoCircleBrowse : public GeoBrowse {
public:
-
+
enum State {
- START ,
+ START ,
DOING_EXPAND ,
DOING_AROUND ,
DONE
} _state;
GeoCircleBrowse( const Geo2dType * g , const BSONObj& circle , BSONObj filter = BSONObj() , const string& type="$center")
- : GeoBrowse( g , "circle" , filter ){
+ : GeoBrowse( g , "circle" , filter ) {
uassert( 13060 , "$center needs 2 fields (middle,max distance)" , circle.nFields() == 2 );
BSONObjIterator i(circle);
@@ -1235,40 +1239,42 @@ namespace mongo {
_state = START;
_found = 0;
- if (type == "$center"){
+ if (type == "$center") {
_type = GEO_PLAIN;
_xScanDistance = _maxDistance;
_yScanDistance = _maxDistance;
- } else if (type == "$centerSphere") {
+ }
+ else if (type == "$centerSphere") {
uassert(13461, "Spherical MaxDistance > PI. Are you sure you are using radians?", _maxDistance < M_PI);
_type = GEO_SPHERE;
_yScanDistance = rad2deg(_maxDistance);
_xScanDistance = computeXScanDistance(_startPt._y, _yScanDistance);
- uassert(13462, "Spherical distance would require wrapping, which isn't implemented yet",
- (_startPt._x + _xScanDistance < 180) && (_startPt._x - _xScanDistance > -180) &&
- (_startPt._y + _yScanDistance < 90) && (_startPt._y - _yScanDistance > -90));
+ uassert(13462, "Spherical distance would require wrapping, which isn't implemented yet",
+ (_startPt._x + _xScanDistance < 180) && (_startPt._x - _xScanDistance > -180) &&
+ (_startPt._y + _yScanDistance < 90) && (_startPt._y - _yScanDistance > -90));
GEODEBUGPRINT(_maxDistance);
GEODEBUGPRINT(_xScanDistance);
GEODEBUGPRINT(_yScanDistance);
- } else {
+ }
+ else {
uassert(13460, "invalid $center query type: " + type, false);
}
ok();
}
- virtual bool moreToDo(){
+ virtual bool moreToDo() {
return _state != DONE;
}
-
- virtual void fillStack(){
- if ( _state == START ){
- if ( ! BtreeLocation::initial( *_id , _spec , _min , _max ,
- _prefix , _found , this ) ){
+ virtual void fillStack() {
+
+ if ( _state == START ) {
+ if ( ! BtreeLocation::initial( *_id , _spec , _min , _max ,
+ _prefix , _found , this ) ) {
_state = DONE;
return;
}
@@ -1276,10 +1282,10 @@ namespace mongo {
}
- if ( _state == DOING_AROUND ){
+ if ( _state == DOING_AROUND ) {
// TODO could rework and return rather than looping
- for (int i=-1; i<=1; i++){
- for (int j=-1; j<=1; j++){
+ for (int i=-1; i<=1; i++) {
+ for (int j=-1; j<=1; j++) {
if (i == 0 && j == 0)
continue; // main box
@@ -1287,10 +1293,11 @@ namespace mongo {
newBox.move(i, j);
PREFIXDEBUG(newBox, _g);
- if (needToCheckBox(newBox)){
+ if (needToCheckBox(newBox)) {
// TODO consider splitting into quadrants
getPointsForPrefix(newBox);
- } else {
+ }
+ else {
GEODEBUG("skipping box");
}
}
@@ -1299,54 +1306,56 @@ namespace mongo {
_state = DONE;
return;
}
-
- if (_state == DOING_EXPAND){
+
+ if (_state == DOING_EXPAND) {
GEODEBUG( "circle prefix [" << _prefix << "]" );
PREFIXDEBUG(_prefix, _g);
while ( _min.hasPrefix( _prefix ) && _min.advance( -1 , _found , this ) );
while ( _max.hasPrefix( _prefix ) && _max.advance( 1 , _found , this ) );
- if ( ! _prefix.constrains() ){
+ if ( ! _prefix.constrains() ) {
GEODEBUG( "\t exhausted the btree" );
_state = DONE;
return;
}
-
+
Point ll (_g, _prefix);
GeoHash trHash = _prefix;
trHash.move( 1 , 1 );
Point tr (_g, trHash);
double sideLen = fabs(tr._x - ll._x);
- if (sideLen > std::max(_xScanDistance, _yScanDistance)){ // circle must be contained by surrounding squares
- if ( (ll._x + _xScanDistance < _startPt._x && ll._y + _yScanDistance < _startPt._y) &&
- (tr._x - _xScanDistance > _startPt._x && tr._y - _yScanDistance > _startPt._y) )
- {
+ if (sideLen > std::max(_xScanDistance, _yScanDistance)) { // circle must be contained by surrounding squares
+ if ( (ll._x + _xScanDistance < _startPt._x && ll._y + _yScanDistance < _startPt._y) &&
+ (tr._x - _xScanDistance > _startPt._x && tr._y - _yScanDistance > _startPt._y) ) {
GEODEBUG("square fully contains circle");
_state = DONE;
- } else if (_prefix.getBits() > 1){
+ }
+ else if (_prefix.getBits() > 1) {
GEODEBUG("checking surrounding squares");
_state = DOING_AROUND;
- } else {
+ }
+ else {
GEODEBUG("using simple search");
_prefix = _prefix.up();
}
- } else {
+ }
+ else {
_prefix = _prefix.up();
}
return;
}
-
+
/* Clients are expected to use moreToDo before calling
* fillStack, so DONE is checked for there. If any more
* State values are defined, you should handle them
- * here. */
+ * here. */
assert(0);
}
- bool needToCheckBox(const GeoHash& prefix){
+ bool needToCheckBox(const GeoHash& prefix) {
Point ll (_g, prefix);
if (fabs(ll._x - _startPt._x) <= _xScanDistance) return true;
if (fabs(ll._y - _startPt._y) <= _yScanDistance) return true;
@@ -1361,8 +1370,8 @@ namespace mongo {
return false;
}
- void getPointsForPrefix(const GeoHash& prefix){
- if ( ! BtreeLocation::initial( *_id , _spec , _min , _max , prefix , _found , this ) ){
+ void getPointsForPrefix(const GeoHash& prefix) {
+ if ( ! BtreeLocation::initial( *_id , _spec , _min , _max , prefix , _found , this ) ) {
return;
}
@@ -1370,17 +1379,17 @@ namespace mongo {
while ( _max.hasPrefix( prefix ) && _max.advance( 1 , _found , this ) );
}
-
- virtual bool checkDistance( const GeoHash& h , double& d ){
- switch (_type){
- case GEO_PLAIN:
- d = _g->distance( _start , h );
- break;
- case GEO_SPHERE:
- d = spheredist_deg(_startPt, Point(_g, h));
- break;
- default:
- assert(0);
+
+ virtual bool checkDistance( const GeoHash& h , double& d ) {
+ switch (_type) {
+ case GEO_PLAIN:
+ d = _g->distance( _start , h );
+ break;
+ case GEO_SPHERE:
+ d = spheredist_deg(_startPt, Point(_g, h));
+ break;
+ default:
+ assert(0);
}
GEODEBUG( "\t " << h << "\t" << d );
@@ -1393,27 +1402,27 @@ namespace mongo {
double _maxDistance; // user input
double _xScanDistance; // effected by GeoDistType
double _yScanDistance; // effected by GeoDistType
-
+
int _found;
-
- GeoHash _prefix;
+
+ GeoHash _prefix;
BtreeLocation _min;
BtreeLocation _max;
- };
+ };
class GeoBoxBrowse : public GeoBrowse {
public:
-
+
enum State {
- START ,
+ START ,
DOING_EXPAND ,
DONE
} _state;
- GeoBoxBrowse( const Geo2dType * g , const BSONObj& box , BSONObj filter = BSONObj() )
- : GeoBrowse( g , "box" , filter ){
-
+ GeoBoxBrowse( const Geo2dType * g , const BSONObj& box , BSONObj filter = BSONObj() )
+ : GeoBrowse( g , "box" , filter ) {
+
uassert( 13063 , "$box needs 2 fields (bottomLeft,topRight)" , box.nFields() == 2 );
BSONObjIterator i(box);
_bl = g->_tohash( i.next() );
@@ -1429,7 +1438,7 @@ namespace mongo {
Point center = _want.center();
_prefix = _g->hash( center._x , center._y );
-
+
GEODEBUG( "center : " << center.toString() << "\t" << _prefix );
{
@@ -1444,42 +1453,43 @@ namespace mongo {
ok();
}
- virtual bool moreToDo(){
+ virtual bool moreToDo() {
return _state != DONE;
}
-
- virtual void fillStack(){
- if ( _state == START ){
- if ( ! BtreeLocation::initial( *_id , _spec , _min , _max ,
- _prefix , _found , this ) ){
+ virtual void fillStack() {
+ if ( _state == START ) {
+
+ if ( ! BtreeLocation::initial( *_id , _spec , _min , _max ,
+ _prefix , _found , this ) ) {
_state = DONE;
return;
}
_state = DOING_EXPAND;
}
-
- if ( _state == DOING_EXPAND ){
+
+ if ( _state == DOING_EXPAND ) {
int started = _found;
- while ( started == _found || _state == DONE ){
+ while ( started == _found || _state == DONE ) {
GEODEBUG( "box prefix [" << _prefix << "]" );
while ( _min.hasPrefix( _prefix ) && _min.advance( -1 , _found , this ) );
while ( _max.hasPrefix( _prefix ) && _max.advance( 1 , _found , this ) );
-
+
if ( _state == DONE )
return;
- if ( ! _prefix.constrains() ){
+ if ( ! _prefix.constrains() ) {
GEODEBUG( "box exhausted" );
_state = DONE;
return;
}
- if (_g->sizeEdge(_prefix) < _wantLen){
+ if (_g->sizeEdge(_prefix) < _wantLen) {
_prefix = _prefix.up();
- } else {
- for (int i=-1; i<=1; i++){
- for (int j=-1; j<=1; j++){
+ }
+ else {
+ for (int i=-1; i<=1; i++) {
+ for (int j=-1; j<=1; j++) {
if (i == 0 && j == 0)
continue; // main box
@@ -1490,36 +1500,37 @@ namespace mongo {
PREFIXDEBUG(newBox, _g);
Box cur( _g , newBox );
- if (_want.intersects(cur)){
+ if (_want.intersects(cur)) {
// TODO consider splitting into quadrants
getPointsForPrefix(newBox);
- } else {
+ }
+ else {
GEODEBUG("skipping box");
}
}
}
_state = DONE;
}
-
+
}
return;
}
}
- void getPointsForPrefix(const GeoHash& prefix){
- if ( ! BtreeLocation::initial( *_id , _spec , _min , _max , prefix , _found , this ) ){
+ void getPointsForPrefix(const GeoHash& prefix) {
+ if ( ! BtreeLocation::initial( *_id , _spec , _min , _max , prefix , _found , this ) ) {
return;
}
while ( _min.hasPrefix( prefix ) && _min.advance( -1 , _found , this ) );
while ( _max.hasPrefix( prefix ) && _max.advance( 1 , _found , this ) );
}
-
- virtual bool checkDistance( const GeoHash& h , double& d ){
+
+ virtual bool checkDistance( const GeoHash& h , double& d ) {
bool res = _want.inside( Point( _g , h ) , _fudge );
- GEODEBUG( "\t want : " << _want.toString()
- << " point: " << Point( _g , h ).toString()
+ GEODEBUG( "\t want : " << _want.toString()
+ << " point: " << Point( _g , h ).toString()
<< " in : " << res );
return res;
}
@@ -1530,23 +1541,23 @@ namespace mongo {
double _wantLen;
int _found;
-
- GeoHash _prefix;
+
+ GeoHash _prefix;
BtreeLocation _min;
BtreeLocation _max;
double _fudge;
- };
+ };
shared_ptr<Cursor> Geo2dType::newCursor( const BSONObj& query , const BSONObj& order , int numWanted ) const {
if ( numWanted < 0 )
numWanted = numWanted * -1;
else if ( numWanted == 0 )
- numWanted = 100;
-
+ numWanted = 100;
+
BSONObjIterator i(query);
- while ( i.more() ){
+ while ( i.more() ) {
BSONElement e = i.next();
if ( _geo != e.fieldName() )
@@ -1554,8 +1565,8 @@ namespace mongo {
if ( e.type() != Object )
continue;
-
- switch ( e.embeddedObject().firstElement().getGtLtOp() ){
+
+ switch ( e.embeddedObject().firstElement().getGtLtOp() ) {
case BSONObj::opNEAR: {
BSONObj n = e.embeddedObject();
e = n.firstElement();
@@ -1564,15 +1575,17 @@ namespace mongo {
GeoDistType type;
if (suffix[0] == '\0') {
type = GEO_PLAIN;
- } else if (strcmp(suffix, "Sphere") == 0) {
+ }
+ else if (strcmp(suffix, "Sphere") == 0) {
type = GEO_SPHERE;
- } else {
+ }
+ else {
uassert(13464, string("invalid $near search type: ") + e.fieldName(), false);
type = GEO_PLAIN; // prevents uninitialized warning
}
double maxDistance = numeric_limits<double>::max();
- if ( e.isABSONObj() && e.embeddedObject().nFields() > 2 ){
+ if ( e.isABSONObj() && e.embeddedObject().nFields() > 2 ) {
BSONObjIterator i(e.embeddedObject());
i.next();
i.next();
@@ -1589,25 +1602,26 @@ namespace mongo {
s->exec();
shared_ptr<Cursor> c;
c.reset( new GeoSearchCursor( s ) );
- return c;
+ return c;
}
case BSONObj::opWITHIN: {
e = e.embeddedObject().firstElement();
uassert( 13057 , "$within has to take an object or array" , e.isABSONObj() );
e = e.embeddedObject().firstElement();
string type = e.fieldName();
- if ( startsWith(type, "$center") ){
+ if ( startsWith(type, "$center") ) {
uassert( 13059 , "$center has to take an object or array" , e.isABSONObj() );
shared_ptr<Cursor> c( new GeoCircleBrowse( this , e.embeddedObjectUserCheck() , query , type) );
- return c;
- } else if ( type == "$box" ){
+ return c;
+ }
+ else if ( type == "$box" ) {
uassert( 13065 , "$box has to take an object or array" , e.isABSONObj() );
shared_ptr<Cursor> c( new GeoBoxBrowse( this , e.embeddedObjectUserCheck() , query ) );
- return c;
+ return c;
}
throw UserException( 13058 , (string)"unknown $with type: " + type );
}
- default:
+ default:
break;
}
}
@@ -1621,41 +1635,41 @@ namespace mongo {
class Geo2dFindNearCmd : public Command {
public:
- Geo2dFindNearCmd() : Command( "geoNear" ){}
- virtual LockType locktype() const { return READ; }
+ Geo2dFindNearCmd() : Command( "geoNear" ) {}
+ virtual LockType locktype() const { return READ; }
bool slaveOk() const { return true; }
void help(stringstream& h) const { h << "http://www.mongodb.org/display/DOCS/Geospatial+Indexing#GeospatialIndexing-geoNearCommand"; }
bool slaveOverrideOk() { return true; }
- bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl){
+ bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
string ns = dbname + "." + cmdObj.firstElement().valuestr();
NamespaceDetails * d = nsdetails( ns.c_str() );
- if ( ! d ){
+ if ( ! d ) {
errmsg = "can't find ns";
return false;
}
vector<int> idxs;
d->findIndexByType( GEO2DNAME , idxs );
-
- if ( idxs.size() > 1 ){
+
+ if ( idxs.size() > 1 ) {
errmsg = "more than 1 geo indexes :(";
return false;
}
-
- if ( idxs.size() == 0 ){
+
+ if ( idxs.size() == 0 ) {
errmsg = "no geo index :(";
return false;
}
int geoIdx = idxs[0];
-
+
result.append( "ns" , ns );
IndexDetails& id = d->idx( geoIdx );
Geo2dType * g = (Geo2dType*)id.getSpec().getType();
assert( &id == g->getDetails() );
-
+
int numWanted = 100;
if ( cmdObj["num"].isNumber() )
numWanted = cmdObj["num"].numberInt();
@@ -1678,35 +1692,35 @@ namespace mongo {
GeoSearch gs( g , n , numWanted , filter , maxDistance , type);
- if ( cmdObj["start"].type() == String){
+ if ( cmdObj["start"].type() == String) {
GeoHash start ((string) cmdObj["start"].valuestr());
gs._start = start;
}
-
+
gs.exec();
double distanceMultiplier = 1;
if ( cmdObj["distanceMultiplier"].isNumber() )
distanceMultiplier = cmdObj["distanceMultiplier"].number();
-
+
double totalDistance = 0;
BSONObjBuilder arr( result.subarrayStart( "results" ) );
int x = 0;
- for ( GeoHopper::Holder::iterator i=gs._hopper->_points.begin(); i!=gs._hopper->_points.end(); i++ ){
+ for ( GeoHopper::Holder::iterator i=gs._hopper->_points.begin(); i!=gs._hopper->_points.end(); i++ ) {
const GeoPoint& p = *i;
-
+
double dis = distanceMultiplier * p._distance;
totalDistance += dis;
-
+
BSONObjBuilder bb( arr.subobjStart( BSONObjBuilder::numStr( x++ ) ) );
bb.append( "dis" , dis );
bb.append( "obj" , p._o );
bb.done();
}
arr.done();
-
+
BSONObjBuilder stats( result.subobjStart( "stats" ) );
stats.append( "time" , cc().curop()->elapsedMillis() );
stats.appendNumber( "btreelocs" , gs._nscanned );
@@ -1715,23 +1729,23 @@ namespace mongo {
stats.append( "avgDistance" , totalDistance / x );
stats.append( "maxDistance" , gs._hopper->farthest() );
stats.done();
-
+
return true;
}
-
+
} geo2dFindNearCmd;
class GeoWalkCmd : public Command {
public:
- GeoWalkCmd() : Command( "geoWalk" ){}
- virtual LockType locktype() const { return READ; }
+ GeoWalkCmd() : Command( "geoWalk" ) {}
+ virtual LockType locktype() const { return READ; }
bool slaveOk() const { return true; }
bool slaveOverrideOk() { return true; }
- bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl){
+ bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
string ns = dbname + "." + cmdObj.firstElement().valuestr();
NamespaceDetails * d = nsdetails( ns.c_str() );
- if ( ! d ){
+ if ( ! d ) {
errmsg = "can't find ns";
return false;
}
@@ -1739,10 +1753,10 @@ namespace mongo {
int geoIdx = -1;
{
NamespaceDetails::IndexIterator ii = d->ii();
- while ( ii.more() ){
+ while ( ii.more() ) {
IndexDetails& id = ii.next();
- if ( id.getSpec().getTypeName() == GEO2DNAME ){
- if ( geoIdx >= 0 ){
+ if ( id.getSpec().getTypeName() == GEO2DNAME ) {
+ if ( geoIdx >= 0 ) {
errmsg = "2 geo indexes :(";
return false;
}
@@ -1750,12 +1764,12 @@ namespace mongo {
}
}
}
-
- if ( geoIdx < 0 ){
+
+ if ( geoIdx < 0 ) {
errmsg = "no geo index :(";
return false;
}
-
+
IndexDetails& id = d->idx( geoIdx );
Geo2dType * g = (Geo2dType*)id.getSpec().getType();
@@ -1764,12 +1778,12 @@ namespace mongo {
int max = 100000;
BtreeCursor c( d , geoIdx , id , BSONObj() , BSONObj() , true , 1 );
- while ( c.ok() && max-- ){
+ while ( c.ok() && max-- ) {
GeoHash h( c.currKey().firstElement() );
int len;
cout << "\t" << h.toString()
- << "\t" << c.current()[g->_geo]
- << "\t" << hex << h.getHash()
+ << "\t" << c.current()[g->_geo]
+ << "\t" << hex << h.getHash()
<< "\t" << hex << ((long long*)c.currKey().firstElement().binData(len))[0]
<< "\t" << c.current()["_id"]
<< endl;
@@ -1778,7 +1792,7 @@ namespace mongo {
return true;
}
-
+
} geoWalkCmd;
}