Filter Expressions
Using filter supported by datastore, one can do filtering on first level as well as filtering on sub-structures of the aggregate.
Filter Expressions allow expressive queries on a set of entities.
Grammar
Please find below a formal (simplified) description of the grammar, that is used for filters.
ROOT: NODE | '(' NODE ')';
NODE: LOGICAL | COMPARISON;
NODE_IN_BRACKET: LOGICAL_IN_BRACKET | COMPARISON_IN_BRACKET;
COMPARISON: COMPARISON_IN_BRACKET | COMPARISON_PLAIN;
COMPARISON_IN_BRACKET: '(' COMPARISON_PLAIN ')';
COMPARISON_PLAIN: PATH OPERATOR VALUE;
LOGICAL: LOGICAL_IN_BRACKET | LOGICAL_PLAIN;
LOGICAL_IN_BRACKET: '(' LOGICAL_PLAIN ')';
LOGICAL_PLAIN: NODE_IN_BRACKET LOGICAL_OPERATOR NODE_IN_BRACKET;
LOGICAL_OPERATOR: 'AND' | 'OR';
OPERATOR: '==' | '=eq=' | '!=' | '=neq=' | '<' | '=lt=' | '<=' | '=lte=' | '>=' | '=gt=' | '>' | '=gte=' | '=*' | '=sc=' | '=in=' | '=nb=' |'=co=' ;
PATH: PROPERTY_NAME_SUFFIX | PROPERTY_NAME_ARTPROP| PROPERTY_NAME_PATH | PROPERTY_ART_PROP;
PROPERTY_NAME_SIMPLE: [a-z]+ (_ [A-Za-z0-9])+;
PROPERTY_NAME_PATH: PROPERTY_NAME_SIMPLE ('.' + PROPERTY_NAME_SIMPLE)*;
PROPERTY_NAME_ARTPROP: PROPERTY_NAME_PATH '.' PROPERTY_ART_PROP;
PROPERTY_NAME_SUFFIX: PROPERTY_NAME_PATH '#' PROPERTY_SUFFIX;
PROPERTY_SUFFIX: 'amount' | 'currency' | LOCALE;
PROPERTY_ART_PROP: '_id' | '_type';
LOCALE: [a-z][a-z] ('_' [A-Z][A-Z])?;
VALUE: STRINGVALUE | NUMBERVALUE | BOOLEANVALUE | NULLVALUE | NODEVALUE | GEOVALUE | STRINGARRAYVALUE;
STRINGVALUE: STRING_TOKEN;
STRING_TOKEN: '"' STRING_PRIMITIVE '"';
STRING_PRIMITIVE: CHAR_PRIMITIVE*;
CHAR_PRIMITIVE: CHAR_ESCAPE | CHAR_NORMAL;
CHAR_ESCAPE: '\"' | '\\';
CHAR_NORMAL: [^\"][^\\];
STRINGARRAYVALUE: '[' STRINGARRAYVALUE_ELEMENTS ']'
STRINGARRAYVALUE_ELEMENTS: STRING_TOKEN (',' STRING_TOKEN)*
NUMBERVALUE: NUMBER_PRIMITIVE;
NUMBER_PRIMITIVE: ('-')? [0-9]+ ('.' [0-9]+)? (('e'|'E')('+'|'-')[0-9]+)?
BOOLEANVALUE: 'true' | 'false';
NULLVALUE: 'null';
NODEVALUE: NODE_IN_BRACKET
GEOVALUE: '[' + NUMBER_PRIMITIVE + ',' + NUMBER_PRIMITIVE + ';' + NUMBER_PRIMITIVE +']';
The basic principle of a filter expression is to define a comparison
. A comparison
consists of
path operator value
, where
path
points to a property of the entity. Traversion of the object tree is supported and is indicated by a.
, that forms a property path within the entity.operator
indicates the operation, that is applied to the comparisonvalue
specifies the value to which the comparsion is applied. It is highly dependent on the type of the property and operation.
A comparison
is grouped by parantheses (path operator value)
.
Comparisons
s can be joined using logical operators.
Operators
Operators can expressed through their symbols as well as through their alias.
For combining different filter criteria the logical operators AND
and OR
can be used.
Name | Symbol | Alias |
EQ | == | =eq= |
NEQ | != | =neq= |
TEXT_STARTS_WITH | ^* | =tsw= |
TEXT_ENDS_WITH | *$ | =tew= |
TEXT_CONTAINS | ** | =tco= |
LT | < | =lt= |
LTE | <= | =lte= |
GTE | >= | =gte= |
GT | > | =gt= |
SUBCLASS | =* | =sc= |
IN | =in= | |
CONTAINS | =co= | |
NEARBY | =nb= |
EQ
Checks for equality between the value of the given property and the specified value.
NEQ
Checks for inequality between the value of the given property and the specified value.
TEXT_STARTS_WITH
Checks if the value of the given property starts with the specified value. The check is not done case sensitive.
TEXT_ENDS_WITH
Checks if the value of the given property ends with the specified value. The check is not done case sensitive.
TEXT_CONTAINS
Checks if the value of the given property contains the specified value. The check is not done case sensitive.
LT
Checks if the value of the given property is lower than the specified value.
LTE
Checks if the value of the given property is lower or equal than the specified value.
GTE
Checks if the value of the given property is greater or equal than the specified value.
GT
Checks if the value of the given property is greater than the specified value.
SUBCLASS
Checks if the value of the given property is a subclass of the specified value.
IN
Checks if the value of the given property is part of the specified array of strings. This check is case sensitive.
CONTAINS
Checks if there exists one object in the list of objects at the given property, which fits to the given filter expression.
NEARBY
Checks if the value of the given property is located in the specified location. The location is expressed by [<lat>,<lon>;<range>]
Defining the path
In general, the path to an object is always relative to the entity which is going to be queried.
Traversion within the object tree can be done via concatenating the names of the properties with a .
.
Despite the modeled properties, there are always two artifical properties avaiable:
_type
The type describes the type of the entity and it's value is given as fully qualified entity name, e.g.core:MyEntity
._id
The id describes the internal id of the entity.
For the property type Currency
there are also two suffixes available (amount
, currency
), which
allow the specification whether the amount (#amount
) value or the currency code currency
of
the property should be compared. The suffix is concated with #
. The suffixes are constant strings.
For the property type Localized Text
, there is also a suffix available. This value is concatened by using
#
followed by an string, that points out to the locale value, that should be compared. Example: #en
Supported operators per property type
According to the type of the property, that is denoted in the path of a comparison node, there are different operators, that are supported.
Property Type | Allowed Operators | Notes |
Text, Text/E-mail,Text/URL | EQ, NEQ, TEXT_STARTS_WITH, TEXT_ENDS_WITH, TEXT_CONTAINS, IN | There is no notion of a wildcard sign available for any of the values. |
Integer, Decimal | EQ, NEQ, LT, LTE, GTE, GT | |
Boolean | EQ, NEQ | |
Currency | EQ, NEQ | Currency cannot be searched without specifying a suffix (#amount resp. #currency ). |
Selection Element | EQ, NEQ, IN | The key of the selection element must be given as comparison value. |
Date, Timestamp | EQ, NEQ, LT, LTE, GTE, GT | The value is passed as a string in format of ISO 8601 (YYYY-MM-DDThh:mm:ss.sssZ ). The precisions for the search is determined by the precision of the given value. |
Geo Point | NB | |
Localized Text | EQ, NEQ, TEXT_STARTS_WITH, TEXT_ENDS_WITH, TEXT_CONTAINS | The value can only be searched, if the locale of the property is specified by suffixing
the property path with #locale , where the locale is given in java-Locale format,
e.g. #en or #en_GB |
Local Entity (single), External Reference (single) | No operators are available at this level, if the property is specified not as a list. But this property can be used to step further into the object tree. | |
Reference (single) | No operators are available. | |
Local Entity (list), External Reference (list), Reference (list) | CONTAINS | List values can be queried by specifying a CONTAINS operator. The given value itself is again a comparison .
If there exists at least one object in the list, that is matching the filter expression, then it evaluates to true.
|
_type (artificial property) | EQ, NEQ, IN, SUBCLASS | Searches for the entity type. |
_id (artificial property) | EQ, NEQ, IN | Searches for the (internal) id of the entity. |
Defining Values
For comparing the value of the given property via some operator, a value must be specified. According to the operator and the type of the property, different types of supplying values are allowed.
String-Value
A simple string, that may contain arbitrary characters. The value needs to be quoted by "
.
For passing the character "
to the value, this character needs to be written as \"
.
For passing the character \
to the value, this character needs to be written as \\
.
Example: "my simple arbitrary string value, that even contains a \" special escaped char."
String-Array-Value
List of strings in array-notation separated by ,
.
Example: ["a", "b", "c"]
Number-Value
A number that may be prefixed by a signum and also contain a decimal value, which is denoted by .
.
Also the scientific represnetation of numbers via e
is allowed.
Example: -23.14
Boolean-Value
A boolean value that can be true
or false
.
Null-Value
Filtering for properties with no value is indicated by the (not quoted) keyword null
.
Example: null
Location-Radius-Value
The value is a combination of the decimals latitude, longitude and range. It will be accepted in the following
format: [<lat>,<lon>;<range>]
.
If the range is negative, this means that it is considered as a minimum distance.
All three elements must be given. The range is the radius in meter around the given geoPoint in which the result must be.
Example: [49.011370,12.095336;5000]
// all elements witin a range of 5km of the point
Example: [700.43,-9999;3]
// invalid value sinc longitude cannot be negative
Example: [49.011370,12.095336;-300]
// minimum distance of 300 m of the given point
Filter-Expressions-Value
This type of value is nothing else than a new filter-expression, that gets evaluated starting on the already reached object. This can also be a complex expression containing more conditions joined by logical operators.
Example: ((myStringProperty=="value") and (myDecimalProperty>=2.45))
Overview of Allowed operators, property types and values
Property Type | Operator | Value Type | Example |
Text, Text/E-mail, Text/URL | EQ | String-Value | myStringProperty=="abc" |
EQ | Null-Value | myStringProperty == null |
|
NEQ | String-Value, Null-Value | myStringProperty != "abc" |
|
IN | String-Array-Value | myStringProperty =in= ["abc", "def"] |
|
TEXT_STARTS_WITH | String-Value | myStringProperty ^* "abc" |
|
TEXT_ENDS_WITH | String-Value | myStringProperty =tew= "abc" |
|
TEXT_ENDS_WITH | String-Value | myStringProperty ** "abc" |
|
Integer, Decimal | EQ | Number-Value, Null-Value | myIntegerProperty == 3 |
NEQ | Number-Value, Null-Value | myDecimalProperty != 3.12 |
|
LT | Number-Value | myDecimalProperty < 4.0e+5 |
|
LTE | Number-Value | myDecimalProperty <= 4.0 |
|
GTE | Number-Value | myIntegerProperty >= 4 |
|
GT | Number-Value | myIntegerProperty > 4 |
|
Currency (amount) | EQ | Number-Value | myCurrencyProperty#amount == 12.22 |
NEQ | Number-Values | myCurrencyProperty#amount != 12.23 |
|
LT | Number-Value | myCurrencyProperty#amount < 4.0e+5 |
|
LTE | Number-Value | myCurrencyProperty#amount <= 4.0 |
|
GTE | Number-Value | myCurrencyProperty#amount >= 4 |
|
GT | Number-Value | myCurrencyProperty#amount > 4 |
|
Currency (currency) | EQ | Number-Value | myCurrencyProperty#currency == "EUR" |
NEQ | Number-Value | myCurrencyProperty#currency != "USD" |
|
Boolean | EQ | Boolean-Value, Null-Value | myBooleanProperty==true |
NEQ | Boolean-Value, Null-Value | myBooleanProperty =neq= false |
|
Selection Element | EQ | String-Value, Null-Value | mySelectionElementProperty == "keyOfFirstElement" |
NEQ | String-Value, Null-Value | mySelectionElementProperty == "keyOfFirstElement" |
|
IN | String-Array-Value | mySelectionElementProperty =in= ["keyOfFirstElement", "keyOfAnotherElement"] |
|
Date, Timestamp | EQ | String-Value (formatted as date), Null-Value | myDateProperty == "2020-03-28" |
NEQ | String-Value (formatted as date), Null-Value | myTimestampProperty != "2020-03-28T13:24:11" |
|
LT | String-Value (formatted as date) | myDateProperty < "2020-03-28" |
|
LTE | String-Value (formatted as date) | myDateProperty <= "2020-03-28" |
|
GTE | String-Value (formatted as date) | myDateProperty >= "2020-03-28" |
|
GT | String-Value (formatted as date) | myDateProperty > "2020-03-28" |
|
Geo Point | NB | Location-Radius-Value | myGeoPointProperty == [49.011370,12.095336;5000] |
Localized Text | EQ | String-Value | myLocalizedProperty#en == "abc" |
NEQ | String-Value | myLocalizedProperty#en_US != "abc" |
|
TEXT_STARTS_WITH | String-Value | myLocalizedProperty#ca_FR =tsw= "abc" |
|
TEXT_ENDS_WITH | String-Value | myLocalizedProperty#de =tew= "abc" |
|
TEXT_ENDS_WITH | String-Value | myLocalizedProperty#en ** "abc" |
|
Local Entity (single), External Reference (single) | Only usable within object tree traversion | myLocalEntity.myStringProperty == "abc" |
|
Local Entity (list) | CONTAINS | Filter-Expressions-Value | myLocalEntityList =co= (myStringPropertyOfLocalEntity == "abc") |
External Reference (list), Reference (list) | CONTAINS | Filter-Expressions-Value | myExternalReferenceList =co= (myStringPropertyOfExternalEntity == "abc") |
_type (artificial property) | EQ | String-Value (specifiying the fully qualified type of the entity) | myLocalEntity._type == "core:MyLocalEntity" |
NEQ | String-Value (specifiying the fully qualified type of the entity) | _type == "core:MyRootEntity" |
|
IN | String-Array-Value (specifiying the fully qualified type of the entity) | myLocalEntity._type =in= ["core:MyLocalEntityA", "core:MyLocalEntityB"] |
|
SUBCLASS | String-Value (specifiying the fully qualified type of the entity) | _type =sc= "core:MyAbstractEntity" |
|
_id (artificial property) | EQ | String-Value | myLocalEntity._id == "5b87e25d-035d-40aa-9209-b0c04b004686" |
NEQ | String-Value | _id != "5b87e25d-035d-40aa-9209-b0c04b004686" |
|
IN | String-Array-Value | myLocalEntity._id =in= ["5b87e25d-035d-40aa-9209-b0c04b004686", "bd8b3a45-3582-40e3-b969-306698a5addf"] |
Example usage within Repository
// Access the repository of the specific root entity and choose the find
// Find takes an object argument and a filter argument. The filter argument is represented as a string.
const rootEntityInstance = this.repo.nsacrnm.RootEntityIdentifier.find(FindConfigurationObj, Filter);
//Example
const rootEntityInstance = this.repo.nsacrnm.RootEntityIdentifier.find(
{ includeSubentities: true,
limit: “2,20”,
sortBy: “customerID,DESC” },
`name == "${name}"`
);
Complex examples
Modeled entities
cc:CreditCard <<root entity>>
- cardText: text
- cardType: selection element [MASTER, VISA, AMEX]
- owner: external reference to cc:Customer
- transactions: list of local entites of type cc:Transaction
cc:Transaction <<abstract entity>>
- transactionName: localized text
- transactionTimestamp: timestamp
cc:DefaultTransaction extends cc:Transaction
- details: text
cc:GoldTransaction extends cc:Transaction
- rating: selection element
cc:Customer <<external entity>>
- custName: text
- custNumber: integer
Query for credit cards with cardType MASTER or VISA
const cards = await this.repo.cc.CreditCard.find(
{ includeSubEntities: true },
`(cardType=in=["MASTER", "VISA"])`
);
Query for credit cards that belong to owner with custNumber 167671
const custNumber = 167671;
const cards = await this.repo.cc.CreditCard.find(
{ includeSubEntities: false },
`owner.custNumber == ${custNumber}`
);
Query for credit cards, which do not have a cardText or which type is not AMEX
const cards = await this.repo.cc.CreditCard.find(
{ includeSubEntities: true },
`((cardText == null) OR (cardType != "AMEX"))`
);
Query for credit cards, which do have a transaction within the last 10 days
const deadline = new Date();
deadline.setUTCDate(deadline.getUTCDate() - 10);
const cards = await this.repo.cc.CreditCard.find(
{ includeSubEntities: true },
`(transactions =co= (transactionTimestamp >= ${deadline.toISOString()}))`
);
Query for credit card with the internal id 5b87e25d-035d-40aa-9209-b0c04b004686
const card = await this.repo.cc.CreditCard.find(
{ includeSubEntities: true },
`_id == "5b87e25d-035d-40aa-9209-b0c04b004686"`
);
Query for credit cards which have one transaction that contains "abc" (english) as transactionName and where the owner is "Black Cat"
const cards = await this.repo.cc.CreditCard.find(
{ includeSubEntities: true },
`((owner.custName == "Black Cat") AND (transactions =co= (transactionName#en =tco= "abc")))`
);
Query for credit cards which have a transaction that is subclass of GoldTransaction
const cards = await this.repo.cc.CreditCard.find(
{ includeSubEntities: true },
`(transactions =co= (_type =sc= "cc:GoldTransaction"))`
);