The POST /noark5/v1/query
or as referred to in the documentation as query
, is the operation for retrieving entitiy details from the Documaster Archive model. The operation allows querying for a single type of entity (or entities from a common type). Flexible query language allows retrieval of entities by complex relations traversal throught the archive structure.
Field | Location | Mandatory | Type | Description |
---|---|---|---|---|
Authorization |
string | access token aquired as part of the authentication call, prefixed with Bearer |
||
Content-Type |
string | content type header, should always be provided as application/json | ||
X-Documaster-Error-Response-Type |
string | custom header indicating that any error should be reported in JSON format, rather than the standard text format, should always be provided as application/json | ||
$.type |
string | type of the core entity to be retrieved by the query (Arkiv , Arkivdel , Saksmappe , Journalpost , etc.). The query can refere to abstract types like AbstraktMappe , AbstraktRegistrering or NasjonalIdentifikator . |
||
$.limit |
number | number of entity objects to be returned as a result of the query. Using limit that is too high may result in slow queries, so consider using a sensible value in accordance with the use case the query is used in. Maximum allowed value for the $.limit parameter is 500. |
||
$.offset |
number | offset of the first result of the query, used when an initial query results exceed the defined limit (indicated in the response by the $.hasMore element set to true) and a consequent calls wants to return the remaining entity objects |
||
$.query |
string | API specific query language expression using parameters defined in $.parameters , details in the Query Language section |
||
$.joins |
object | object in which each element name is an alias definition and the value is the reference field of the entity object to which the alias points. Take a look at the Query Joins section. | ||
$.joins.{alias} |
string | join alias for the reference field in the value. The alias should be prefixed with #. Aliases can be included in other aliases, as soon as all of them are defined in the same query. | ||
$.parameters |
object | object with elements for each parameter used in $.query , should always be provided in case specific query is used |
||
$.parameters.{paramName} |
string | name of the parameter as used in the $.query element, the name of the element must be prefixed with @ indicating it is a parameter and should contain only letters and digits (no special symbols are supported, like underscores). The value of the parameter can be one of the following : date , string , number , boolean ,null . Note that null values can be used to check for fields which are not set, including reference fields. |
||
$.sortOrder[] |
array | list of sorting parameters to be applied on the returned entity objects, each of the elemetn $.sortOrder[].field and $.sortOrder[].order are required for the elements of the array |
||
$.sortOrder[].field |
string | entity field used to sort over. Note that reference fields (prefixed with ref ) cannot be used to sort over |
||
$.sortOrder[].order |
string | sorting order, supported values are asc and desc | ||
$.publicUse |
boolean | true/false value indicating whether screened entities should be returned or not. Default is true indicating no screened entities will be returned. |
Example of a simple query using parameters can be found in the Getting Starter/First API Interaction section. Sample queries for every core entity type can be found in the Examples section.
A more complex query utilizing parameters, joins and sorting follows. The sample query below queries for any type of Folders, through basic type AbstraktMappe
type, that has 2 distinct secondary classes, referenced through refSekundaerKlasse
field. One of the classes is with id 1111, while the other one has an class identity APIC2. The results are sorder by the folder identity element mappeIdent
. Note that some of the response entities fields in the response are omitted from the sample for clarity.
Although the example below uses joins, it is done mainly for illustrating possible operation uses. Most practical use cases do not require use of joins or complex deep reference chaining to filter results.
Request
POST https://<documaster-instance>.local.documaster.tech:8083/rms/api/public/noark5/v1/query HTTP/1.1
...
Authorization: Bearer {{accessTokenIntegrator}}
Content-Type: application/json
X-Documaster-Error-Response-Type: application/json
{
"type": "AbstraktMappe",
"limit": 10,
"query": "#secClass1.id = @class1Id && #secClass2.klasseIdent = @class2Ident",
"parameters" : {
"@class1Id" : "1111",
"@class2Ident" : "APIC2"
},
"joins": {
"#secClass1" : "refSekundaerKlasse",
"#secClass2" : "refSekundaerKlasse"
},
"sortOrder" : [
{
"field" : "mappeIdent",
"order" : "desc"
}
]
}
Response
HTTP/1.1 200 OK
...
Content-Type: application/json
HTTP/1.1 200 OK
Connection: close
Date: Mon, 06 Dec 2021 09:57:13 GMT
Content-Type: application/json
{
"hasMore": false,
"results": [
{
"type": "Saksmappe",
"id": "1122",
"version": "10",
"fields": {
"opprettetAv": "External Integrator ACME",
"mappeIdent": "2021/7",
"tittel": "API Created Case File - 2",
"beskrivelse": "Second API created Case File",
"dokumentmedium": "E",
"saksaar": 2021,
"sakssekvensnummer": 7,
"administrativEnhet": "AD1",
"saksansvarlig": "External Integrator ACME",
"saksstatus": "B"
},
"links": {
"refPrimaerKlasse": 681,
"refArkivdel": 688
}
},
{
"type": "Saksmappe",
"id": "981",
"version": "14",
"fields": {
"opprettetAv": "External Integrator ACME",
"mappeIdent": "2021/6",
"tittel": "API Created Case File",
"beskrivelse": "First API created Case File",
"dokumentmedium": "E",
"saksaar": 2021,
"sakssekvensnummer": 6,
"administrativEnhet": "AD1",
"saksansvarlig": "External Integrator ACME",
"saksstatus": "B"
},
"links": {
"refPrimaerKlasse": 681,
"refArkivdel": 688
}
}
]
}
QueryResponse<AbstraktMappe> qrMappe = client.query(
AbstraktMappe.class,
"#secClass1.id = @class1Id && #secClass2.klasseIdent = @class2Ident", 100)
.addQueryParam("@class1Id", "1111")
.addQueryParam("@class2Ident", "APIC2")
.addJoin("#secClass1", "refSekundaerKlasse")
.addJoin("#secClass2", "refSekundaerKlasse")
.addSortOrder("mappeIdent", Order.DESCENDING)
.execute();
if (!qrMappe.getResults().isEmpty()) {
AbstraktMappe folder = qrMappe.getResults().iterator().next();
if (folder instanceof Saksmappe) {
Saksmappe caseFile = (Saksmappe)folder;
System.out.println(caseFile.getTittel());
}
}
QueryResponse<AbstraktMappe> qrMappe = client.Query<AbstraktMappe>(
"#secClass1.id = @class1Id && #secClass2.klasseIdent = @class2Ident", 100)
.AddQueryParam("@class1Id", "1111")
.AddQueryParam("@class2Ident", "APIC2")
.AddJoin("#secClass1", "refSekundaerKlasse")
.AddJoin("#secClass2", "refSekundaerKlasse")
.AddSortOrder("mappeIdent", Order.Descending)
.Execute();
if (qrMappe.Results.Count() > 0)
{
AbstraktMappe folder = qrMappe.Results.First();
if (folder is Saksmappe)
{
Saksmappe caseFile = (Saksmappe)folder;
Console.WriteLine(caseFile.Tittel);
}
}
Response of the operation is an array($.results
), with the entity objects matching the specified $.query
in the request. The matched entity objects are returned with their complete representation and no filtering on the entity fields is supported currently.
Successful execution of the query would result in an HTTP 200 OK response as shown in the example above.
Field | Location | Mandatory | Type | Description |
---|---|---|---|---|
Content-Type |
string | content type header, always returned as application/json | ||
$.hasMore |
boolean | indicates whether there are more results which are not returned as part of this response. This field should be used as an indicator that subsequent queries should be made with the required $.offset parameter set to the value of previous query $.offset value + previous query $.limit value. |
||
$.results[] |
array | list of entities which match the query parameters. The array can be empty in case no entity matches the criteris. In case it is not empty, the objects below should contain the $.results[].id , $.results[].type , $.results[].version and $.results[].fields elements. |
||
$.results[].type |
string | type of the entity being returned. The value matches the request $.type element if concrete types are used for the query. If a basic type is used, one of AbstraktMappe , AbstraktRegistrering or NasjonalIdentifikator ), the response contains the real type of the entity. No basic types are returned in the response. |
||
$.results[].id |
string | unique numeric identifier of the entity object in the Documaster Archive | ||
$.results[].version |
string | version of the entity object, used for optimistic locking | ||
$.results[].fields.{fieldName} |
any | all the fields of the entity objects, excluding reference fields (prefixed with ref ) |
||
$.results[].links.{referenceField} |
string | important reference fields and their values identifying other entities in the structure. Note that not all reference fields are returned, check the documentation of the respective entity for reference fields that would be returned. |
As part of the resposne, business specific metadata is also returned for those entities that has it under $.results[].fields.virksomhetsspesifikkeMetadata
. The table below provides the details about BSM values returned. The full path of the elemetns for BSM is shortened for clarity.
Field | Location | Mandatory | Type | Description |
---|---|---|---|---|
$..<bsm>.{bsmGroupID} |
object | element under $.results[].fields.virksomhetsspesifikkeMetadata.{bsmGroupID} , business specific metadata definition for the bsm groupID configured for the entity. BSM data is returned only for the following set of entities : Basic Folder(Mappe ), Meeting Folder(Moetemappe ), Case File (Saksmappe ), Case Party (Sakspart ), Basic Record (Registrering ), Meeting Record (Moeteregistrering ), Registry Entry (Journalpost ), Correspondence Party (Korrespondansepart ), Document (Dokument ), and Class (Klasse ) |
||
$..<bsm>.{bsmGroupID}.{bsmFieldID} |
object | element under $.results[].fields.virksomhetsspesifikkeMetadata.{bsmGroupID}.{bsmFieldID} , business specific metadata field part of the BSM group identified by {bsmGroupID} |
||
$..<bsm>.{bsmGroupID}.{bsmFieldID}.type |
object | element under $.results[].fields.virksomhetsspesifikkeMetadata.{bsmGroupID}.{bsmFieldID}.type , type of the BSM field, supported values are string , long , double , timestamp , and encrypted |
||
$..<bsm>.{bsmGroupID}.{bsmFieldID}.value |
object | element under $.results[].fields.virksomhetsspesifikkeMetadata.{bsmGroupID}.{bsmFieldID}.value , value of the BSM field assigned to the entity object |
query
operation utilizes a flexible languge for filtering returned entities based on either queried entities fields or field of linked entities. The linked entity objects can be directly referenced by the queried objects or through another reference field. Query string is an optional one in the request payload in $.query
element, but it rarely makes sense to use the operation without a query set.
Queries are comprised of expressions. The expressions can be simple, like equal (=
), not equal (!=
) or like (%=
). The expressions can be range like between inclusive ([@param1:@param2]
), between exclusive ({@param1:@param2}
) and combinations of both (defined by the type of bracket used). Expressions can be grouped ((
, )
) and also logical oparators can be used between them, like logical and (&&
) and logical or (||
). Details of the expressions and their usage is provided below.
Literal values are not part of the $.query
string, they are assigned a parameter in $.parameters
object and the parameter is used in the queries. Each paraemeter name is prefixed with @ (at symbol). The parameters are referenced with the “@” prefix in both the $.parameters
object and in $.query
string.
Expression | Data Type | Description |
---|---|---|
field = @param |
number, string, reference (ref ) |
matches objects having fields equal to the value of the parameter. Notice the following: string values are compared in a case sensitive way reference fields ( ref ) can be compared only with a parameter which is set to null to check if the reference is set at all |
field != @param |
number, string, reference (ref ) |
matches objects having fields different from the value of the parameter. |
field %= @param |
number, string | matches objects having fields like the value of the parameter. The value of the parameter should contains % symbol at the relevant place where any symbols should be matched |
Using the value of ***** in a paramter value denotes any value.
Entity Type $.type |
Query $.query |
Parameters $.parameters |
Description |
---|---|---|---|
Fonds (Arkiv ) |
“id = @fondsID” | “@fondsID” : 123 | filters the Fonds (Arkiv ) the consumer has access to, to only one Fonds (Arkiv ) with ID = 123 |
CaseFile (Saksmappe ) |
“tittel %= @title && saksaar = @year” | “@title” : “%API%”, "@year" : 2021 |
fitlers the CaseFiles (Saksmappe ) having title that contains string ‘API’ (anywhere in the title, indicated by the two % signs on both sides) and year (saksaar ) equal to 2021 |
Registry Entry (Journalpost ) |
“refPrimaerKlasse.id = @primaryClass && (refEksternId=@null || refEksternId.eksterntSystem != @externalSystemID)” |
“@primaryClass” : 567, "@null" : null, "@externalSystemID" : “ES123” |
filters all Registry Entries (Journalpost ) having primary class of 576 and don’t have an external ID set at all, or if set, it does not match the value of “ES123” |
Range expressions allow filtering based on a range of values. Using [
or ]
brackets indicates that the limit value is also included in the result set, while {
and }
indicate the limit values should be excluded. Both type of brackets can be combined in a single query.
Expression | Data Type | Description |
---|---|---|
field = [@param1:@param2] |
date, number | matches objects where a field is in the inclusive range (containing also the range values) between the two parameter values |
field = {@param1:@param2} |
date, number | matches objects where a field is in the exclusive range (excluding the range values) between the two parameter values |
Entity Type $.type |
Query $.query |
Parameters $.parameters |
Description |
---|---|---|---|
CaseFile (Saksmappe ) |
“saksaar = [@yearFrom:@yearTo}” | “@yearFrom” : 2000, "@yearTo" : 2021 |
fitlers the CaseFiles (Saksmappe ) having year (saksaar ) between 2000 and 2020, note that 2021 is excluded because of the } bracket used |
Registry Entry (Journalpost ) |
“registreringsDato = [@startDate:@endDate]” | “@startDate” : “2021-10-01”, "@endDate" : “2021-12-01” |
filters all Registry Entries (Journalpost ) having date of registration (registreringsDato ) between 01.10.2021 and 01.12.2021 including those two dates. Note that the dates can contain also hour component, it is a standard ISO 8601 date format. |
The query language provides two logical operators that can be used between expressions: logical and - &&
and logical or - ||
. Examples of their usage is already present in the examples above. Additionally in order to change evaluation order, the query language suppors grouping of the expressions using (
and )
.
As shown in the examples below, reference fields (prefixed with ref
) can be used to access linked entity objects and use their fields to filter returned entity objects set. Using the dot notation (.) to access reference entity object fields is a simple way to access referenced objects up or down the archive structure. Reference chaining denotes a single path to a linked entity object, which means that if single reference is used more than once in the same query to filter for two distinct referenced objects, the query will not return the expected results.
To give a better idea what is meant by single path imagine the case where there is a single RegistryEntry (Journalpost
) having two external IDs (EksternID
) associated with it. First External ID (EksternID
) has a external system name (eksterntSystem
) set to “IS1” and the second one has the same external system name set to “IS2”. Executing a query like this :
{
"type": "Journalpost",
"limit": 100,
"query": "refEksternId.eksterntSystem = @externalSystemID1 && refEksternId.eksterntSystem = @externalSystemID2",
"parameters" : {
"@externalSystemID1": "IS1",
"@externalSystemID2": "IS2"
}
}
returns an empty set, although there is a Registry Entry (Journalpost
) having both external IDs associated with it. The reason is the single path that the reference defines, it is referencing either one of the two external IDs (EksternId
), but not both. Having the logical and &&
operator used causes the response to be empty. Changing the logical operator to ||
will also not work, because in this case the query would return registry entries that have either one of the two externalIDs (with external system set to the required values), while we want to retrieve those tha have both external IDs. Same is valid for any reference field that can reference multiple related entities, like secondary classes reference from a case file or registry entry.
Reference fields can be chained thus allowing executing queries throughout the entities levels as in the example below, thus allowing deep level of references chaining. The sample below queries for the Record (‘AbstractRegistrering’) which is linked to the Document (Dokument
) which is linked to the Document Version (‘Dokumentversjon’) with ID = 56434.
{
"type": "AbstraktRegistrering",
"query": "refDokument.refDokumentversjon.id = @documentVersionID",
"limit": 1,
"parameters": {
"@documentVersionID": "56434"
}
}
Although query joins sounds like a very common approach for querying data from the archvie, they have relatively limited use cases. Common use case for query joins is to select an entity linked to two (or more) other entities archive entities.
Examples :
- Query for a case file with two secondar classes
- Query for an entity with two distinct external IDs associated to it
Joins are a way of defining aliases to reference fields, which practically allows using the aliases as separate paths through the archive structure. Joins are defined in the $.joins
element of the query request, where each element in the $.joins
object is an alias to a reference field. Aliases are prefixed with #
(hash symbol). Taking the query above and making it work with joins is done like this:
{
"type": "Journalpost",
"limit": 100,
"query": "#refExternId1.eksterntSystem = @externalSystemID1 && #refExternId2.eksterntSystem = @externalSystemID2",
"joins": {
"#refExternId1" : "refEksternId",
"#refExternId2" : "refEksternId"
},
"parameters" : {
"@externalSystemID1": "IS1",
"@externalSystemID2": "IS2"
}
}
As seen in the sample above, there are two join aliases #refExternID1
and #refExternID2
which refer to the same refEksternId
field of the Registry Entry (Journalpost
). This time though, both aliases define two separate paths in the structure and havin the query using those aliases, rather than directly the reference field gives the expected results, retrieving only the Registry Entries (Journalpost
) having both externalIDs from systems with names IS1
and IS2
.