RLabkey makeFilter with filters as variable?

LabKey Support Forum
RLabkey makeFilter with filters as variable? Ben Bimber  2018-01-15 15:04
Status: Closed
 
This is hopefully a simple question for anyone who knows R better. RLabkey allows you to make a filter using the makeFilter function:

makeFilter(c('myColumn', EQUALS,'value1'), c('myColumn2',EQUALS,'value2))

you can see that makeFilter uses R's elipsis argument, and this is read as a vector of vectors (i think?):

https://github.com/cran/Rlabkey/blob/49299ba7b5eaf5127d8dca8dba2f38739dff6454/R/makeFilter.R

I'd like to build up my filter list upstream in code, such as:

filters <- c(
     c('myColumn', EQUALS,'value1'),
     c('myColumn2',EQUALS,'value2)
)
makeFilter(filters)

or as a list:

filters <- list(
     c('myColumn', EQUALS,'value1'),
     c('myColumn2',EQUALS,'value2)
)
makeFilter(filters)

This seems like a very basic thing to do. However, in each case this will not work. c() in R recursively flattens out all my lists. list() isnt the correct type expected by makeFilter(). I cant see any way to make an R variable convert into the variable argument R expects with '...'. Is there a way to do this? Thanks in advance.
 
 
Jon (LabKey DevOps) responded:  2018-01-15 15:45
Hi Ben,

Are you using "EQUALS" or "EQUAL"?

Using the export option on a grid to get the R code, the filter normally appears like this:

    colFilter=makeFilter(c("myColumn", "EQUAL", "value1"),c("myColumn2", "CONTAINS", "value2")),

For example:

labkey.data <- labkey.selectRows(
    baseUrl="http://localhost:8080/labkey",
    folderPath="/myProject",
    schemaName="lists",
    queryName="myList",
    viewName="",
    colFilter=makeFilter(c("myColumn", "EQUAL", "value`"),c("myColumn2", "CONTAINS", "value2")),
    containerFilter=NULL
)

I tested this out on my end using the following code which worked for me:

library(Rlabkey)

myFilter <- (c("firstField", "EQUAL", "value1"),c("secondField", "EQUAL", "value2"))

labkey.data <- labkey.selectRows(
    baseUrl="http://localhost:8080/labkey",
    folderPath="/myProject",
    schemaName="lists",
    queryName="myList",
    viewName="",
    colFilter=makeFilter(myFilter),
    containerFilter=NULL
)

labkey.data


Regards,

Jon
 
Ben Bimber responded:  2018-01-15 15:55
HI Jon

Yes, i mis-typed EQUALS/EQUAL, though that's not the problem here. The example you added is exactly like what I posted at the start of the thread:

makeFilter(c("myColumn", "EQUAL", "value1"), c("myColumn2", "CONTAINS", "value2")),

That is calling makeFilter with a list of vectors, each of which represents a filter. I'd like to build up this list of filters dynamically in code before calling makeFilter(). More like the following (which does not work):

#start with some default filters
filters <- list(
     c('myColumn', EQUAL,'value1'),
     c('myColumn2',EQUAL,'value2)
)

#some event in code determines whether to add more filters
if (something == true){
  filters <- append(filters, c('myColumn3',EQUAL,'value3))
}

#now pass my dynamically created list to makeFilter()
makeFilter(filters)

There must be a way to do this. As i posed above, in Rlabkey, makeFilter uses '...', R's elipsis argument, which seems vaguely like java varargs; however, I cant figure out a way to pass in a datatype to makeFilter() that will work. I basically need a vector of vectors, though i cant figure out how to get R to generate that.
 
Jon (LabKey DevOps) responded:  2018-01-15 16:09
Thanks for confirming Ben.

I've pinged Cory to review this and respond on the post. It looks like what you're doing should work, but I'm certain we're just missing something here.

Thanks,

Jon
 
cnathe responded:  2018-01-15 18:53
Ben,
Looking at the code for the Rlabkey makeFilter.R source, when you pass in multiple c() vectors as args to makeFilter, we pass those long to rbind(...). So we row bind the vectors together to get a single object that we then iterate over. So the following produce equivalent results

1. calling makeFilter() directly with two vectors
makeFilter(c("ParticipantId", "EQUAL", "101"), c("Lymphs", "EQUAL", "1300"))

2. building up a single object using rbind and then passing that to makeFilter()
filters = c("ParticipantId", "EQUAL", "101")
filters = rbind(filters,c("Lymphs", "EQUAL", "1300"))
makeFilter(filters)

So you should be able to do the same as #2 and build up your filters object in code.
Let me know if that doesn't help and I can look into it more.
Thanks,
Cory
 
Ben Bimber responded:  2018-01-15 19:44
hi cory,

are you sure about that example? from what i can tell, R converts the rbind of the two vectors into a list. at least from everything i tried, when you pass a list to makeFilter you either get an error or filters not being applied (because it was being interpreted as a single long vector). I was able to find:
do.call(makeFilter, argList). from the earlier example, it's sometihng like:


filters <- list(
     c('myColumn', EQUAL,'value1'),
     c('myColumn2',EQUAL,'value2)
)
filter <- do.call(makeFilter, filters)

and this seems to work.
 
cnathe responded:  2018-01-15 19:55
From my local testing using R version 3.4.2 with Rlabkey version 2.1.136, querying against the Demo Study on labkey.org gives back the same 2 rows for both of the following code examples:

1. code from the export to R script from the LabKey dataset grid view:

library(Rlabkey)
labkey.data <- labkey.selectRows(
    baseUrl="https://www.labkey.org",
    folderPath="/home/Demos/Study/demo",
    schemaName="study",
    queryName="Demographics",
    colFilter=makeFilter(c("Country/CountryName", "EQUAL", "USA"),c("Gender/GenderName", "EQUAL", "m"),c("Language/LanguageId", "EQUAL", "French"))
)

2. code from #1 modified to generate the filters object using rbind

library(Rlabkey)
filters = c("Country/CountryName", "EQUAL", "USA")
filters = rbind(filters, c("Gender/GenderName", "EQUAL", "m"))
filters = rbind(filters, c("Language/LanguageId", "EQUAL", "French"))
labkey.data <- labkey.selectRows(
    baseUrl="https://www.labkey.org",
    folderPath="/home/Demos/Study/demo",
    schemaName="study",
    queryName="Demographics",
    colFilter=makeFilter(filters)
)
 
Ben Bimber responded:  2018-01-15 20:14
OK, that seems right. I dont understand exactly what kind of R datatype rbind is giving us, but it does work. your second solution is probably easiest though this seems to give the same result:

filters = list(
  c("Country/CountryName", "EQUAL", "USA"),
  c("Gender/GenderName", "EQUAL", "m")
)
filters = append(filters, list(c("Language/LanguageId", "EQUAL", "French")))

labkey.data2 <- labkey.selectRows(
  baseUrl="https://www.labkey.org",
  folderPath="/home/Demos/Study/demo",
  schemaName="study",
  queryName="Demographics",
  colFilter=do.call(makeFilter, filters)
)
print(nrow(labkey.data2))

thanks for the help.