Filters for Data Reading

Filters are widely used throughout the Groovy API. You will find them in all kinds of search calls where they are used to filter data.

You might also want to read the section Searching API to find out how filters are actually used.

In this section:

Creating Filters

Filter objects can be instantiated and manipulated with the Filter class static methods:

Groovy
def myFilter = Filter.equal("name", "Bob");  // creates a filter with the OP_EQUAL operator

The following filtering operators are available:

Operator

Notes

Example

EQUAL


Groovy
Filter.equal("name", "Bob")

NOT_EQUAL


Groovy
Filter.notEqual("age", 5)

GREATER_THAN


Groovy
Filter.greaterThan("age", 5)

GREATER_OR_EQUAL


Groovy
Filter.greaterOrEqual("name", "M")

LESS_THAN


Groovy
Filter.lessThan("name", "N")

LESS_OR_EQUAL


Groovy
Filter.lessOrEqual("age", 65)

IN

Equals to one of the items in the list of values. The value can be a collection or an array.

Groovy
Filter.in("eyeColor", EyeColor.BLUE, EyeColor.HAZEL)

NOT_IN


Groovy
Filter.notIn("hairColor", HairColor.BROWN, HairColor.BLACK)

LIKE

Takes an SQL like expression.

Groovy
Filter.like("name", "Wil%")

ILIKE

LIKE + ignore case
(Some databases ignore case by default.)

Groovy
Filter.ilike("name", "wil%")

NULL

SQL IS NULL 

Groovy
Filter.isNull("primaryDoctor")

NOT_NULL


Groovy
Filter.isNotNull("phone")

EMPTY

NULL or empty string or empty collection/association

info Note that this filter is not supported in the Analytics module (PA). As a result, it cannot be used in the following modules:

Groovy
Filter.isEmpty("children")

NOT_EMPTY

info Note that this filter is not supported in the Analytics module (PA). As a result, it cannot be used in the following modules:

Groovy
Filter.isNotEmpty("primaryDoctor.firstName")

SOME

Applies to collection/association properties. Takes another Filter as a value, and matches when at least one of the values in the collection matches the filter.

info Note that this filter is not supported in the Analytics module (PA). As a result, it cannot be used in the following modules:

Groovy
Filter.some("children", Filter.equal("name", "Joey")) 

//has a child named 'Joey'

ALL

The same as SOME, except that all values must match the filter.

info Note that this filter is not supported in the Analytics module (PA). As a result, it cannot be used in the following modules:

Groovy
Filter.all("children", Filter.greaterOrEqual("age", 18)) 
//all children are 18 or older

NONE

The same as SOME, except that none of the values may match the filter.

info Note that this filter is not supported in the Analytics module (PA). As a result, it cannot be used in the following modules:

Groovy
Filter.none("pets", Filter.and(Filter.equal("species", "cat"), Filter.lessThan("age", .75)) 

//has no cats under 9 months old


AND

Takes no property. Takes an array or collection of Filters as a value. Matches when all the filters in the value match.

Groovy
Filter.and(Filter.greaterOrEqual("age", 40), Filter.lessThan("age", 65))

OR

The same as AND, except that it matches when any of the filters match.

Groovy
Filter.or(Filter.like("firstName", "Wil%"), Filter.like("lastName", "Wil%"))

NOT

Takes no property. Takes a single Filter as a value. Matches when the filter in the value does not match.

Groovy
Filter.not(Filter.ilike("name", "W%")) 

//name does not start with 'w'

Available from version 15.0

To address issues with unsupported filters in the Analytics module, the Advanced Configuration Option silenceUnsupportedFilterError has been implemented. For more information see Advanced Configuration Options - Full List.

When building complex filters, it is recommended to format the code in a structure like this:

Groovy
def myFilter =
    Filter.or(
        Filter.equal("name", "Jack"),
        Filter.and(
            Filter.equal("name", "Jill"),
            Filter.like("location", "%Chicago%"),
            Filter.greaterThan("age", 5)
        )
    )

Using Filters

To get the idea how you can use a filter, see the following example:

Groovy
def prices = api.productExtension("ListPrices", Filter.equal("sku", api.product("sku")), Filter.lessOrEqual("attribute1", 200))

In this example, the query returns all rows from Product Extension called "ListPrices" which are assigned to the current product and whose price is less or equal to 200.

For more examples see Data Reading Functions where the filters are used extensively.

Tidying up Filters

Filters are very often used for multiple fields and writing many filters in one row makes the code not well readable and produces long lines like this:

Unreadable code
Groovy
Filter.equal("name", "Promotions"), 
Filter.equal("sku", api.product("sku")), 
Filter.equal("attribute2","Fix price"), 
Filter.lessOrEqual("attribute5", targetTimestamp), 
Filter.greaterOrEqual("attribute6", targetTimestamp)
def rec = api.find("PX", )

A better approach is to group them in a list and save into a variable:

Readable code
Groovy
def filters = [
  Filter.equal("name", "Promotions"),
  Filter.equal("sku", api.product("sku")),
  Filter.equal("attribute2", "Fix price"),
  Filter.lessOrEqual("attribute5", targetTimestamp),  // from
  Filter.greaterOrEqual("attribute6", targetTimestamp),  // to
]

Then use the Spread operator * to expand this list to function parameters:

Groovy
def rec = api.find("PX", *filters)

The code style above is more readable and reusable. It can be easily copied and quickly adjusted.

If you need to parametrize the filters, you can create a function that returns such a list instead:

Parametrized filter
Groovy
def productStructureFilters(lookupTableName, itemCategory, productGroup, manufacturer) {
  return [
    Filter.equal("lookupTable.uniqueName", lookupTableName),
    Filter.equal("key1", itemCategory),
    Filter.equal("key2", productGroup),
    Filter.equal("key3", manufacturer)
  ]
}

And here is the sample call:

Groovy
def rec = api.find("MLTV3", *productStructureFilters(lookupTableName, itemCategory, productGroup, manufacturer))

Known Issues

Filtering on NULL Values with Filter.notEqual() Returns No Rows

When filtering on NULL values together with the Filter.notEqual() filter, you must be aware of the fact that DB treats NULL values as unknown, which could result in an unexpected behavior.

See the following example. Let's say we want to retrieve all values except when Attribute1 equals 'A'.

SKU

Label

Attribute1

001

Product 1

NULL

002

Product 2

NULL

003

Product 3

A

The common sense tells you to use Filter.notEqual("attribute1", "A") but this returns no rows. That is because you need to treat the NULL values using Filter.isNull() or Filter.isNotNull().

The following code works:

Groovy
Filter.or(
  Filter.isNull("attribute1"), 
  Filter.notEqual("attribute1", "A")
)

Further Reading

As the whole filtering API is largely based on an opensource project (but not 100% identical anymore), you may also have a look at their documentation. Chances are that the options described there will also work in the Groovy code:

https://code.google.com/archive/p/hibernate-generic-dao/