Live documentation for the development version.
In many use cases, the response should only contain objects that pertain to some specific criteria.
The $filter
request parameter makes it possible to filter the data to be returned based on the values of specific attributes of the requested data.
Thus, one could request all values above a certain threshold or measured between two specific points in time.
The following request returns all Observations where the result value is greater than 5:
http://…/Observations?$filter=result gt 5
This request provides the following response:
{
"@iot.count" : 8,
"@iot.nextLink" : "/v1.1/Observations?$filter=result gt 5&$top=4&$skip=4",
"value" : [
{
"phenomenonTime" : "2016-06-22T13:21:31.144Z",
"resultTime" : null,
"result" : 10,
"@iot.id" : 34,
"@iot.selfLink" : "/FROST-Server/v1.1/Observations(34)"
}, {
…
}, {
…
}, {
…
}
]
}
When adding constant values in filters, like the 5
in the example above, care has to be taken that those
values are properly encoded so the server correctly recognises the value. The following table lists
how constants are encoded in URLs.
URLs must also be URL-Encoded before being sent to the server. In most cases the browser takes care of this,
but in case of times with time-zones that contain a +
character, this URL-Encoding does not always happen
automatically.
Type | encoding | example |
---|---|---|
numbers | direct in URL | result gt 5 |
strings | quoted with ' , quotes doubled |
name eq 'Hylke''s Thing' |
times | direct in URL | phenomenonTime ge phenomenonTime ge 2022-12-23T13:21:31%2B01:00 (URL Encoded from 2022-12-23T13:21:31+01:00 ) |
durations | duration'<ISO 8601 code>' |
phenomenonTime gt now() sub duration'P1D' |
geometries | geography'<WKT geometry>' |
st_within(location, geography'POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))') |
The following shows operators that can be used when composing complex filter requests.
Operator | Description | Example |
---|---|---|
eq | Equal | /ObservedProperties?$filter=name eq ‘CO2’ |
ne | Not equal | /ObservedProperties?$filter=name ne ‘CO2’ |
gt | Greater than | /Observations?$filter=result gt 5 |
ge | Greater than or equal | /Observations?$filter=result ge 5 |
lt | Less than | /Observations?$filter=result lt 5 |
le | Less than or equal | /Observations?$filter=result le 5 |
Operator | Description | Example |
---|---|---|
and | Logical and | /Observations?$filter=result le 5 and FeatureOfInterest/id eq ‘1’ |
or | Logical or | /Observations?$filter=result gt 20 or result le 3.5 |
not | Logical negation | /Things?$filter=not startswith(description,’test’) |
Operator | Description | Example |
---|---|---|
( ) | Precedence grouping | /Observations?$filter=(result sub 5) gt 10 |
To make it easier to get the correct order of parameters in functions, remember that in general, functions can be be read as:
parameter1 functionname parameter2
For example:
name startswith 'room'.
String matches are case sensitive. String constants are quoted with single-quotes ('
) while single-quotes are doubled:
name eq 'Bob''s Thing'
Function | Description & Example |
---|---|
substringof(s1, s2) bool |
Returns true if s1 is a substring of s2 Things?$filter=substringof('room', name) matches livingroom and room S01 |
endswith(s1, s2) bool |
Returns true if s1 ends with s2 Things?$filter=endswith(name, 'room') matches livingroom but not room S01 |
startswith(s1, s2) bool |
Returns true if s1 starts with s2 Things?$filter=startswith(name, 'room') matches room S01 but not livingroom |
substring(s1, i1) string |
Returns the substring of s1, starting at position i1 substring(description,1) eq 'ensor Things' |
substring(s1, i1, i2) string |
Returns the substring of s1, starting at position i1, with length i2 substring(description,2,4) eq 'nsor' |
length(s1) int |
Returns the length of string s1 length(description) eq 13 |
indexof(s1, s2) int |
Returns the index of s2 in s1 indexof(description,'Sensor') eq 1 |
tolower(s1) string |
Returns the lower case version of s1 tolower(description) eq 'sensor things' |
toupper(s1) string |
Returns the upper case version of s1 toupper(description) eq 'SENSOR THINGS' |
trim(s1) string |
Returns the string s1, with whitespace trimmed from start and end trim(description) eq 'Sensor Things' |
concat(s1, s2) string |
Returns a string composed of s2 added to the end of s1 concat(concat(unitOfMeasurement/symbol,', '), unitOfMeasurement/name) eq 'degree, Celsius' |
Mathematical functions work on all fields that are numeric, and on numerical constants.
Function | Description & Example |
---|---|
round(n1) int |
Returns n1 rounded to the nearest integer round(result) eq 42 matches 41.50 to 42.49 |
floor(n1) int |
Returns n1, rounded down to the nearest integer less than n1 floor(result) eq 42 matches 42.00 to 42.99 |
ceiling(n1) int |
Returns n1, rounded up to the nearest integer larger than n1 ceiling(result) eq 42 matches 41.01 to 42.00 |
Geospatial functions work on all geospatial fields (Location/location and FeatureOfInterest/feature) and on geospatial constants.
Geospatial constants can be specified by using WKT enclosed in geography'…'
, for example:
geography'POINT (30 10)'
geography'LINESTRING (30 10, 10 30, 40 40)'
geography'POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))'
Function | Description & Example |
---|---|
geo.intersects(g1, g2) bool |
Returns true if g1 intersects g2 geo.intersects(location, geography'POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))') |
geo.length(g1) number |
Returns the length of geometry g1 geo.length(location) lt 2 matches all locations that are linestrings with a length less than 2 degrees |
geo.distance(g1, g2) number |
Returns the distance between g1 and g2 in the units of the server (generally degrees) geo.distance(location, geography'POINT (30 10)') lt 1 |
st_equals(g1, g2) bool |
Returns true if g1 is the same as g2 st_equals(location, geography'POINT (30 10)') |
st_disjoint(g1, g2) bool |
Returns true if g1 is separated from g2 st_disjoint(location, geography'POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))') |
st_touches(g1, g2) bool |
Returns true if g1 touches g2 st_touches(location, geography'LINESTRING (30 10, 10 30, 40 40)') |
st_within(g1, g2) bool |
Returns true if g1 is within g2 st_within(location, geography'POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))') |
st_overlaps(g1, g2) bool |
Returns true if g1 overlaps g2 st_overlaps(location, geography'POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))') |
st_crosses(g1, g2) bool |
Returns true if g1 crosses g2 st_crosses(location, geography'LINESTRING (30 10, 10 30, 40 40)') |
st_intersects(g1, g2) bool |
Returns true if g1 intersects g2 st_intersects(location, geography'LINESTRING (30 10, 10 30, 40 40)') |
st_contains(g1, g2) bool |
Returns true if g1 contains g2 st_contains(location, geography'POINT (30 10)') |
st_relate(g1, g2, s1) bool |
Returns true if g1 has a relation with g2 given the intersection matrix pattern s1 st_relate(location, geography'POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))', 'T********') |
Temporal functions other than now()
operate on the time as stored in the server.
For FROST-Server this is always in the time zone UTC, but for other servers this may also be the time zone of the original value as it was stored.
For time-constants, use ISO8601 format, with time zone, without quotes. Make sure the URL is correctly URL-Encoded so the +
in the time zone is not lost.
Observations?$filter=phenomenonTime ge 2022-01-01T00:00:00+00:00
URL-Encodes to
Observations?$filter=phenomenonTime ge 2022-01-01T00:00:00%2B00:00
Function | Description & Example |
---|---|
now() datetime |
Returns the current time, in the timezone of the server phenomenonTime lt now() |
mindatetime() datetime |
Returns the minimum time that can be stored in the server |
maxdatetime() datetime |
Returns the maximum time that can be stored in the server |
date(t1) date |
Returns the date part of time t1 date(resultTime) ne date(validTime) |
time(t1) time |
Returns the time part of time t1 time(phenomenonTime) le time(1990-01-01T12:00:00Z) returns all observations taken between midnight and noon |
year(t1) int |
Returns the year part of time t1 year(phenomenonTime) eq 2015 |
month(t1) int |
Returns the month part of time t1 month(phenomenonTime) eq 12 |
day(t1) int |
Returns the day part of time t1 day(phenomenonTime) eq 31 |
hour(t1) int |
Returns the hour part of time t1 hour(phenomenonTime) eq 23 |
minute(t1) int |
Returns the minute part of time t1 minute(phenomenonTime) eq 59 |
second(t1) int |
Returns the second part of time t1 second(phenomenonTime) eq 59 |
fractionalseconds(t1) double |
Returns the millisecond part of time t1 fractionalseconds(phenomenonTime) eq 0 |
totaloffsetminutes(t1) int |
Returns the offset part of time t1 totaloffsetminutes(phenomenonTime) eq 60 |
Grouping functions allow clients to search for items in lists or sets.
Clients can use any()
to search in related entity sets and in
to search in properties.
Function | Description & Example |
---|---|
in bool |
Returns true if the item on the left is in the array on the right. properties/countryCode in ('IT','NL') 'myTag' in properties/tags |
relatedSet/any(x: <predicate>) |
Returns true if any of the Entities in the set match the predicate. Datastreams/any(d: d/ObservedProperty/name eq 'NO2') |
Give me all Things that have both Datastreams that measure NO2 and Datastreams that measure O3:
v1.1/Things?$filter=Datastreams/any(d1: d1/ObservedProperty/name eq 'NO2') and Datastreams/any(d2: d2/ObservedProperty/name eq 'O3')
Give me all Things that have Datastreams that have Observations in the last 10 minutes that exceed the threshold specified in the Datastream:
v1.1/Things?$filter=Datastreams/any(d: d/Observations/any(o: o/phenomenonTime ge now() sub duration'PT10m' and o/result gt d/properties/threshold))