↓ Skip to main content
A pen and ink drawing of a wooden sieve on a workbench. A heap of teal blocks in many shapes lies on its metal plate with square holes. Below the sieve, in a tray, a row of seven small orange cubes stands where they fell through. Calipers, a stack of blank cards and a red cloth lie around it.

The oslc.where Clause in the Maximo REST API

Every list the Maximo REST API returns can be narrowed with one query parameter, oslc.where. It looks like SQL, and it is a different language with its own grammar. This article shows the grammar, what Manage accepts, and the mistakes that end in a 400.

The rules here come from IBM’s documentation and from our own work with the REST API, on Manage in the MAS 9.2 series. We ran every clause on our test system, against IBM’s demo data, as a user without administrator rights. The examples use the object structures MXAPIASSET and MXAPIWODETAIL, which ship with Manage.

Our product Fiedler Data Export uses this clause. When an export reads Manage through an object structure, the condition you type on the Export page goes to Manage as oslc.where. So this article is also the reference for that field.

Where the clause goes
#

oslc.where is a query parameter of a GET request on an object structure. The other parameters decide what each record carries and how the answer looks. This request returns the operating assets of the site BEDFORD, three columns each:

curl -G "https://<your-host>/maximo/api/os/mxapiasset" \
  -H "apikey: <your-api-key>" \
  --data-urlencode 'lean=1' \
  --data-urlencode 'oslc.select=assetnum,siteid,status' \
  --data-urlencode 'oslc.where=siteid="BEDFORD" and status="OPERATING"'

--data-urlencode matters here. The clause holds quotes, spaces, % signs and sometimes a +, and all of them must reach Manage encoded. Every HTTP library has an equivalent, for example URLSearchParams in JavaScript. In the rest of this article the clauses are shown unencoded, so they are easy to read.

The shape of a term
#

A clause is a list of terms joined with and. Each term is an attribute name, an operator and a value, written without spaces:

siteid="BEDFORD" and status="OPERATING" and priority>=2

Four rules decide whether Manage can read a term:

  • No space around the operator. siteid="BEDFORD" works. siteid = "BEDFORD" is refused with a parse error. A space after the attribute name tells the parser that in comes next.
  • Text and dates go in double quotes. Single quotes are SQL, and the parser stops at the first one. A text value without quotes is refused too.
  • Numbers and booleans have no quotes. priority>=2, moved=0 and moved=false all work.
  • Attribute names and and ignore case. SITEID="BEDFORD" AND status="OPERATING" gives the same records.

A plain attribute name must belong to the main object of the object structure. On MXAPIASSET that is ASSET. An unknown name is refused with its own message, which names the property it could not find.

Operators and values
#

You wantWriteNote
equalstatus="OPERATING"exact match for text
not equalstatus!="OPERATING"
greater, lesspriority>1, priority<=3numbers and dates
a rangepriority>=2 and priority<=3the same attribute twice
one of a liststatus in ["OPERATING","NOT READY"]also numbers: priority in [1,2]
none of a listsiteid!="[BEDFORD,BOSTON]"needs at least two values
starts withassetnum="11%"
containsdescription="%pump%"
does not containstatus!="%OPER%"a NOT LIKE
has a valueserialnum="*"is not null
has no valueserialnum!="*"is null

The in list may hold patterns as well. assetnum in ["11%","12%"] returns the assets whose number starts with 11 or with 12.

How text is compared
#

Without a %, the = operator looks for the exact value. status="OPERATING" finds the operating assets, and status="OPER" finds nothing. With a % at the start or the end, the value becomes a pattern. Case played no part in any of our runs: status="operating" returned the same records as status="OPERATING".

One exception needs care. Some attributes have the search type TEXT in Database Configuration. On our system ASSET.DESCRIPTION is one of them. For such an attribute, description="pump" is a word search. It found the descriptions that contain the word “pump” and left out one that contains “Pumper”. description="%pump%" found both. So write the % signs when you mean a pattern.

Dates
#

A date is an ISO 8601 text in double quotes. The time and the offset may be left out:

installdate>="2010-01-01T00:00:00-05:00"
installdate>="2010-01-01"

Watch the + of a positive offset. A server decodes a raw + in a URL as a space. Then 2024-01-01T00:00:00+01:00 arrives as 2024-01-01T00:00:00 01:00, and Manage answers with BMXAA4144E, “The date/time format is not valid”. The error message even shows the space. Encode the sign as %2B, or let your HTTP library encode the whole clause.

The NOT IN trap
#

siteid!="[BEDFORD,BOSTON]" leaves out both sites. With one value, siteid!="[BEDFORD]", Manage compares the site with the text [BEDFORD], brackets included. No site has that name, so the clause returns every asset, BEDFORD included. Use siteid!="BEDFORD" for one value.

IBM’s filtering page says that NOT IN only works for ALN attributes. It works for numbers as well: priority!="[1,2]" returns the assets whose priority is neither 1 nor 2.

That clause leaves out the assets with no priority at all. != and NOT IN behave as in SQL, and an empty value matches neither = nor !=. To keep those records, add a group for them:

(priority!="[1,2]") or (priority!="*")

Related records#

A dot follows a relationship of the business object. This returns the assets whose location is operating:

location.status="OPERATING"

location is the name of a relationship of ASSET, as Database Configuration lists it. The location is not part of MXAPIASSET, and the clause still works, because a dot path can use any relationship of the business object. A path can go further, one relationship per step, and the last part is always an attribute.

A relationship can also be counted. _dbcount compares the number of related rows. This returns the assets with more than one meter:

assetmeter._dbcount>1

The same family has _dbsum, _dbavg, _dbmax and _dbmin after an attribute, for example <relationship>.<attribute>._dbsum>100.

Braces filter the parents by a child of the object structure. This returns the assets that have a meter named TEMP-F:

assetmeter{metername="TEMP-F"}

Inside the braces stands the child’s name in the object structure, and the terms inside follow the same rules as above.

Combining with or
#

A plain or is refused. siteid="BEDFORD" or siteid="BOSTON" ends in BMXAA8744E. Manage accepts OR in two other forms.

The first form puts each part in parentheses. Each group may hold several terms joined with and:

(siteid="BEDFORD" and priority=1) or (siteid="BOSTON")

The second form is the extra parameter opmodeor=1. It joins every term of the clause with OR:

oslc.where=siteid="BEDFORD" and siteid="BOSTON"&opmodeor=1

For one attribute, in is the simplest choice. siteid in ["BEDFORD","BOSTON"] returns the same records as (siteid="BEDFORD") or (siteid="BOSTON").

Values Manage fills in for you
#

Some values are replaced on the server before the query runs:

  • "-dfltsite-" and "-dfltorg-" become the default site and organization of the user who calls.
  • "-personid-", "-userid-" and "-laborcode-" become that user’s person, user name and labor code.
  • "~OPERATING~", with tildes, is a synonym’s internal value. Manage expands it to every status whose internal value is OPERATING. Your system may have more than one, so status="~OPERATING~" can return more records than status="OPERATING". With != it becomes a NOT IN over all of them.

So siteid="-dfltsite-" gives each user the assets of their own default site, with one clause for everybody.

How Manage reads a clause
#

This picture follows a clause from the URL to the records, and it shows at which step each error comes:

The way of an oslc.where clause through Manage, and the error each step gives The way of an oslc.where clause through Manage, and the error each step gives
The way of an oslc.where clause through Manage, and the error each step gives

The middle step is the key to the whole syntax. IBM’s own pages say that oslc.where maps to the Query by Example framework, QBE for short. Each term becomes a QBE value on the business object, and Manage writes the SQL from those values. So the clause can only say what QBE can say, and that is why raw SQL is refused.

A savedQuery parameter in the same request is added to the clause with AND. Fiedler Data Export uses that combination: you pick a saved query of the application, and your condition narrows it further.

Errors at a glance
#

ClauseAnswerFix
siteid = "BEDFORD"400 BMXAA8744Eremove the spaces
siteid='BEDFORD'400 BMXAA8744Euse double quotes
siteid=BEDFORD400 BMXAA8744Equote the text
siteid="BEDFORD" or siteid="BOSTON"400 BMXAA8744Euse groups, in or opmodeor=1
foo="x"400 BMXAA8781Euse an attribute of the main object
a date with a raw +400 BMXAA4144Eencode it as %2B
siteid!="[BEDFORD]"200, every sitewrite siteid!="BEDFORD"

The message of BMXAA8744E names the column where the parser stopped. That number points straight at the fault.

Examples
#

Each clause below returned records on our test system. The object structure is named above each one.

Operating assets of one site (MXAPIASSET):

siteid="BEDFORD" and status="OPERATING"

Assets of two sites (MXAPIASSET):

siteid in ["BEDFORD","BOSTON"]

Assets without a serial number at the caller’s default site (MXAPIASSET):

serialnum!="*" and siteid="-dfltsite-"

Assets at an operating location, with a TEMP-F meter (MXAPIASSET):

location.status="OPERATING" and assetmeter{metername="TEMP-F"}

Approved or started work orders of priority 1 or 2 (MXAPIWODETAIL):

status in ["APPR","INPRG"] and wopriority<=2

Work orders reported in 2024 (MXAPIWODETAIL):

reportdate>="2024-01-01" and reportdate<"2025-01-01"

Priority 1 assets at BEDFORD, and every asset at BOSTON (MXAPIASSET):

(siteid="BEDFORD" and priority=1) or (siteid="BOSTON")

What comes next
#

IBM’s own pages on filtering are the reference to keep next to this article:

How Fiedler Data Export reads Manage through an object structure, and where this clause comes in, is in Two Ways to Read Manage. If you want help with the REST API in your own Manage, our services page shows how we work, or get in touch.

IBM and Maximo are trademarks of International Business Machines Corporation, registered in many jurisdictions worldwide.