Search code examples
rrmongodb

r - rmongodb $or query construction


Background

I have GTFS data stored in a local mongodb database.

The calendar table looks like

field      | type
service_id | varchar
monday     | int (0 or 1)
tuesday    | int (0 or 1)
...
sunday     | int (0 or 1)

Task

I would like to select all the service_ids for which any weekday (Monday to Friday) = 1, using the rmongodb package in r.

In SQL this would be something like: SELECT service_id FROM calendar WHERE monday = 1 OR tuesday = 1 OR ... OR friday = 1

Detail

When using the Robomongo GUI the query is:

db.getCollection('calendar').find({"$or" : 
    [{'monday':1},
    {'tuesday':1},
    {'wednesday':1},
    {'thursday':1},
    {'friday':1}]
})

which returns 8 documents (see image)

robomongoQuery

Therefore, in r I'm trying to construct the same or query that will return the same results, but I'm not having any luck.

library(rmongodb)
library(jsonlite)
## connect to db
mongo <- mongo.create()
mongo.is.connected(mongo)
db <- "temp"

## days for which I want a service:
serviceDays <- c("monday","tuesday","wednesday","thursday","friday")

Attempt 0:

## create list as the 'query' condition
ls <- list("$or" = 
         list("monday" = 1L, 
              "tuesday" = 1L, 
              "wednesday" = 1L, 
              "thursday" = 1L, 
              "friday" = 1L))

services <- mongo.find.all(mongo, "temp.calendar", query=ls)
## returns error:
Error in mongo.find(mongo, ns, query = query, sort = sort, fields = fields,  : 
  find failed with unknown error.

Attempt 1:

## paste the string together
js <- paste0('{"', serviceDays, '":[',1L,']}', collapse=",")
js <- paste0('{"$or" :[', js, ']}')
## this string has been validated at jsonlint.com

bs <- mongo.bson.from.JSON(js)
## run query
services <- mongo.find.all(mongo, "temp.calendar", query=bs)
## result
> services
list()    ## empty list

## manually writing the JSON string doesn't work either
# js <- '{"$or" : [{"monday":[1]},{"tuesday":[1]},{"wednesday":[1]},{"thursday":[1]},{"friday":[1]}]}'

Attempt 2:

## create the or condition using R code
l <- as.list(sapply(serviceDays, function(y) 1L))
bs <- mongo.bson.from.list(list("$or" = list(l)))
## run query
services <- mongo.find.all(mongo, "temp.calendar", query=bs)
## result
> length(services)
[1] 2    ## 2 documents returned

The two documents returned are for service_ids where all of monday, tuesday, wednesday, thursday, friday = 1. i.e., it seems to have used an AND clause, not an OR.

Attempt 3:

## deconstruct the JSON string (attempt 1)
js <- fromJSON(js, simplifyVector=FALSE)
bs <- mongo.bson.from.list(js)

## run query
services <- mongo.find.all(mongo, "temp.calendar", query=bs)
## result
> services
list()    ## empty list

what's wrong with my query attempts in R that prevents me getting the same 8 documents I get when using the Robomongo GUI?


Solution

  • My 'attempt 0' was close, but I was missing more list arguments.

    ls <- list("$or" = list(list("monday" = 1L), 
                        list("tuesday" = 1L), 
                        list("wednesday" = 1L), 
                        list("thursday"= 1L), 
                        list("friday" = 1L)))
    ## json string:
    > toJSON(ls)
    {"$or":[{"monday":[1]},{"tuesday":[1]},{"wednesday":[1]},{"thursday":[1]},{"friday":[1]}]} 
    ## run query:
    services <- mongo.find.all(mongo, "temp.calendar", query=ls)
    
    ## result
    length(services)
    [1] 8