dselivanov / rmongodb

R driver for MongoDB
53 stars 26 forks source link

Unable to query a 2dsphere index #30

Closed robinvanemden closed 10 years ago

robinvanemden commented 10 years ago

I am trying to run find on a 2dsphere index (http://docs.mongodb.org/manual/tutorial/query-a-2dsphere-index/) using rmongodb 1.4.2

db.places.find( { loc :
                  { $geoWithin :
                    { $geometry :
                      { type : "Polygon" ,
                        coordinates : 
                         [ [ [ 2 , 50 ] ,  [ 3 , 50 ] ,[ 3 , 51 ] , [ 2 , 51 ], [ 2 , 50 ] ] ]
                } } } } )

Yet though this works perfectly within MongoDB commandline, I am unable to get this to work using:

string <- paste0('{ "loc" : { "$geoWithin" : { "$geometry" : { type : "Polygon" ,"coordinates": [ [ [',longitude,', ',latitude,'], [',longitude+1,', ',latitude,'], [',longitude+1,', ',latitude+1,'], [',longitude,', ',latitude+1,'], [',longitude,', ',latitude,'] ] ] } } } }')
query <- mongo.bson.from.JSON (string)

The resulting string can be fed into a commandline find, works ok:

db.SR_Data_Collection_1.count( { "loc" : { "$geoWithin" : { "$geometry" : { "type" : "Polygon" ,"coordinates": [ [ [2, 50], [3, 50], [3, 51], [2, 51], [2, 50] ] ] } } } })

I am able to run find on a 2d index, like so:

string <- paste0('{ "loc" : { "$within" : { "$box" : [[',longitude,', ',latitude,'], [',longitude+1,', ',latitude+1,']] } } }')    
query <- mongo.bson.from.JSON (string)

The only major difference seems to be the "nestedness" of the JSON in the 2dsphere find - maybe the [[[]]] array is the problem?

schmidb commented 10 years ago

Yes, there is currently an issue with JSON to BSON conversion for arrays in JSON objects. Thanks a lot for submitting the problem. I am working on a solution with the jsonlite package maintainer. For now you can create manually a correct BSON object using mongo.bson.X.

robinvanemden commented 10 years ago

Thank you for your quick reply! I was able to make this work through monog.bson.X, for those needing a 2sphere index find (excerpt from code finding 1 by 1 degrees squares through a loop of longitudes/latidudes)

buf<-mongo.bson.buffer.create()
mongo.bson.buffer.start.object(buf, "loc")
mongo.bson.buffer.start.object(buf, "$geoWithin")
mongo.bson.buffer.start.object(buf, "$geometry")
mongo.bson.buffer.append.string(buf,"type","Polygon")
mongo.bson.buffer.start.array(buf,"coordinates")
mongo.bson.buffer.start.array(buf,"0")

mongo.bson.buffer.start.array(buf,"0")
mongo.bson.buffer.append.double(buf,"0",longitude)
mongo.bson.buffer.append.double(buf,"1",latitude)
mongo.bson.buffer.finish.object(buf)    

mongo.bson.buffer.start.array(buf,"1")
mongo.bson.buffer.append.double(buf,"0",longitude+1)
mongo.bson.buffer.append.double(buf,"1",latitude)
mongo.bson.buffer.finish.object(buf)

mongo.bson.buffer.start.array(buf,"2")
mongo.bson.buffer.append.double(buf,"0",longitude+1)
mongo.bson.buffer.append.double(buf,"1",latitude+1)
mongo.bson.buffer.finish.object(buf)

mongo.bson.buffer.start.array(buf,"3")
mongo.bson.buffer.append.double(buf,"0",longitude)
mongo.bson.buffer.append.double(buf,"1",latitude+1)
mongo.bson.buffer.finish.object(buf)

mongo.bson.buffer.start.array(buf,"4")
mongo.bson.buffer.append.double(buf,"0",longitude)
mongo.bson.buffer.append.double(buf,"1",latitude)
mongo.bson.buffer.finish.object(buf)

mongo.bson.buffer.finish.object(buf)
mongo.bson.buffer.finish.object(buf)
mongo.bson.buffer.finish.object(buf)
mongo.bson.buffer.finish.object(buf)
mongo.bson.buffer.finish.object(buf)
query<-mongo.bson.from.buffer(buf)

Just for information, this results in the following, correct, query:

> print(query)
    loc : 3      
        $geoWithin : 3   
            $geometry : 3    
                type : 2     Polygon
                coordinates : 4      
                    0 : 4    
                        0 : 4    
                            0 : 1    8.000000
                            1 : 1    54.000000

                        1 : 4    
                            0 : 1    8.250000
                            1 : 1    54.000000

                        2 : 4    
                            0 : 1    8.250000
                            1 : 1    54.250000

                        3 : 4    
                            0 : 1    8.000000
                            1 : 1    54.250000

                        4 : 4    
                            0 : 1    8.000000
                            1 : 1    54.000000

As compared to the result of the following, broken, query <- mongo.bson.from.JSON (see first comment)

    loc : 3      
        $geoWithin : 3   
            $geometry : 3    
                type : 2     Polygon
                coordinates : 3      
                    1 : 3    
                        1 : 3    
                            1 : 1    8.000000
                            2 : 1    54.000000

                        2 : 3    
                            1 : 1    9.000000
                            2 : 1    54.000000

                        3 : 3    
                            1 : 1    9.000000
                            2 : 1    55.000000

                        4 : 3    
                            1 : 1    8.000000
                            2 : 1    55.000000

                        5 : 3    
                            1 : 1    8.000000
                            2 : 1    54.000000
jeroen commented 10 years ago

This has nothing to do with JSON or jsonlite. See this issue.

dselivanov commented 10 years ago

Now all works as expected:

longitude <- 50.1
latitude <- 50.1
string <- paste0('{ "loc" : { "$geoWithin" : { "$geometry" : { "type" : "Polygon" ,"coordinates": [ [ [',longitude,', ',latitude,'], [',longitude+1,', ',latitude,'], [',longitude+1,', ',latitude+1,'], [',longitude,', ',latitude+1,'], [',longitude,', ',latitude,'] ] ] } } } }')
bson <- mongo.bson.from.JSON(string)
print(bson)
loc : 3      
        $geoWithin : 3   
            $geometry : 3    
                type : 2     Polygon
                coordinates : 4      
                    0 : 4    
                        0 : 4    
                            0 : 1    50.100000
                            1 : 1    50.100000

                        1 : 4    
                            0 : 1    51.100000
                            1 : 1    50.100000

                        2 : 4    
                            0 : 1    51.100000
                            1 : 1    51.100000

                        3 : 4    
                            0 : 1    50.100000
                            1 : 1    51.100000

                        4 : 4    
                            0 : 1    50.100000
                            1 : 1    50.100000
robinvanemden commented 9 years ago

Thank you!