FIWARE Core Context Management NGSI LD JSON LD

Description: This tutorial introduces linked data concepts to the FIWARE Platform. The supermarket chain’s store finder application is recreated using NGSI-LD and the differences between the NGSI v2 and NGSI-LD interfaces are highlighted and discussed. The tutorial is a direct analogue of the original getting started tutorial but uses API calls from the NGSI-LD interface.

The tutorial uses cUrl commands throughout, but is also available as Postman documentation.

Run in Postman Run in GitPod


Adding Linked Data concepts to FIWARE Data Entities.

“Six degrees of separation doesn't mean that everyone is linked to everyone else in just six steps. It means that a very small number of people are linked to everyone else in a few steps, and the rest of us are linked to the world through those special few.”

― Malcolm Gladwell, The Tipping Point

The introduction to FIWARE Getting Started tutorial introduced the NGSI v2 interface that is commonly used to create and manipulate context data entities. An evolution of that interface has created a supplementary specification called NGSI-LD as a mechanism to enhance context data entities through adding the concept of linked data. This tutorial will introduce the background of the ideas behind the new interface and compare and contrast how to create and manipulate data entities as linked data.

Additional tutorials in the series will further discuss data relationships an how to create context data entities using linked data enabling the full knowledge graph to be traversed.

What is Linked Data?

All users of the Internet will be familiar with the concept of hypertext links, the way that a link on one web page is able to guide the browser to loading another page from a known location.

Whilst humans are able to understand relationship discoverability and how links work, computers find this much more difficult, and require a well-defined protocol to be able to traverse from one data element to another held in a separate location.

Creating a system of readable links for computers requires the use of a well defined data format (JSON-LD) and assignation of unique IDs (URLs or URNs) for both data entities and the relationships between entities so that semantic meaning can be programmatically retrieved from the data itself.

Properly defined linked data can be used to help answer big data questions, and the data relationships can be traversed to answer questions like "Which products are currently available on the shelves of Store X and what prices are they sold at?"

Video: What is Linked Data?

Click on the image above to watch an introductory video on linked data concepts.

JSON-LD is an extension of JSON , it is a standard way of avoiding ambiguity when expressing linked data in JSON so that the data is structured in a format which is parsable by machines. It is a method of ensuring that all data attributes can be easily compared when coming from a multitude of separate data sources, which could have a different idea as to what each attribute means. For example, when two data entities have a name attribute how can the computer be certain that is refers to a "Name of a thing" in the same sense (rather than a Username or a Surname or something). URLs and data models are used to remove ambiguity by allowing attributes to have a both short form (such as name) and a fully specified long form (such http://schema.org/name) which means it is easy to discover which attribute have a common meaning within a data structure.

JSON-LD introduces the concept of the @context element which provides additional information allowing the computer to interpret the rest of the data with more clarity and depth.

Furthermore the JSON-LD specification enables you to define a unique @type associating a well-defined data model to the data itself.

Video: What is JSON-LD?

Click on the image above to watch a video describing the basic concepts behind JSON-LD.

What is NGSI-LD?

NGSI-LD is an evolution of the NGSI v2 information model, which has been modified to improve support for linked data (entity relationships), property graphs and semantics (exploiting the capabilities offered by JSON-LD). This work has been conducted under the ETSI ISG CIM initiative and the updated specification has been branded as NGSI-LD. The main constructs of NGSI-LD are: Entity, Property and Relationship. NGSI-LD Entities (instances) can be the subject of Properties or Relationships. In terms of the traditional NGSI v2 data model, Properties can be seen as the combination of an attribute and its value. Relationships allow to establish associations between instances using linked data.

NGSI v2 Data Model

As a reminder, the NGSI v2 data model is quite simple. It can be summarized as shown below:

The core element of NGSI v2 is the data entity, typically a real object with a changing state (such as a Store, a Shelf and so on). Entities have attributes (such as name and location) and these in turn hold metadata such as accuracy - i.e. the accuracy of a location reading.

Every entity must have a type which defines the sort of thing the entity describes, but giving an NGSI v2 entity the type=Store is relatively meaningless as no-one is obliged to shape their own Store entities in the same fashion. Similarly, adding an attribute called name doesn't suddenly make it hold the same data as someone else's name attribute.

Relationships can be defined using NGSI v2, but only so far as giving the attribute an appropriate attribute name defined by convention ( e.g. starting with ref, such as refManagedBy) and assigning the attribute type=Relationship which again is purely a naming convention with no real semantic weight.

NGSI LD Data Model

The NGSI LD data model is more complex, with more rigid definitions of use which lead to a navigable knowledge graph.

Once again, entity can be considered to be the core element. Every entity must use a unique id which must be a URI, often a URN, there is also a type, used to define the structure of the data held, which must also be a URI. This URI should correspond to a well-defined data model which can be found on the web. For example the URI https://uri.fiware.org/ns/dataModels#Building is used to define common data model for a Building.

Entities can have properties and relationships. Ideally the name of each property should also be a well-defined URI which corresponds to a common concept found across the web (e.g. http://schema.org/address is a common URI for the physical address of an item). The property will also have a value which will reflect the state of that property (e.g. name="Checkpoint Markt"). Finally a property may itself have further properties (a.k.a. properties-of-properties) which reflect further information about the property itself. Properties and relationships may in turn have a linked embedded structure (of properties-of-properties or properties-of-relationships or relationships-of-properties or relationships-of-relationships etc.) which lead to the following:

An NGSI LD Data Entity (e.g. a supermarket):

  • Has an id which must be unique. For example urn:ngsi-ld:Building:store001,
  • Has type which should be a fully qualified URI of a well defined data model. For example https://uri.fiware.org/ns/dataModels#Building. Authors can also use type names, as short hand strings for types, mapped to fully qualified URIs through the JSON-LD @context.
  • Has property of the entity, for example, an address attribute which holds the address of the store. This can be expanded into http://schema.org/address, which is known as a fully qualified name (FQN).
  • The address, like any property will have a value corresponding to the property address (e.g. Bornholmer Straße 65, 10439 Prenzlauer Berg, Berlin
  • Has a property-of-a-property of the entity, for example a verified field for the address.
  • Has a relationship of the entity, for example, a managedBy field where the relationship managedBy corresponds to another data entity : urn:ngsi-ld:Person:bob-the-manager
  • The relationship managedBy, may itself have a property-of-a-relationship (e.g. since), this holds the date Bob started working the store
  • The relationship managedBy, may itself have a relationship-of-a-relationship (e.g. subordinateTo), this holds the URN of the area manager above Bob in the hierarchy.

As you can see the knowledge graph is well defined and can be expanded indefinitely.

Relationships will be dealt with in more detail in a subsequent tutorial.

Architecture

The demo application will send and receive NGSI-LD calls to a compliant context broker. Since both NGSI v2 and NGSI-LD interfaces are available to an experimental version fo the Orion Context Broker, our demo application will only make use of one FIWARE component.

Currently, the Orion Context Broker relies on open source MongoDB technology to keep persistence of the context data it holds. Therefore, the architecture will consist of two elements:

  • The Orion Context Broker which will receive requests using NGSI-LD
  • The underlying MongoDB database :
    • Used by the Orion Context Broker to hold context data information such as data entities, subscriptions and registrations.

Since all interactions between the two elements are initiated by HTTP requests, the elements can be containerized and run from exposed ports.

The necessary configuration information can be seen in the services section of the associated docker-compose.yml file:

Orion Configuration

orion:
    image: quay.io/fiware/orion-ld
    hostname: orion
    container_name: fiware-orion
    depends_on:
        - mongo-db
    networks:
        - default
    ports:
        - '1026:1026'
    command: -dbhost mongo-db -logLevel DEBUG
    healthcheck:
        test: curl --fail -s http://orion:1026/version || exit 1

Mongo DB Configuration

mongo-db:
    image: mongo:4.2
    hostname: mongo-db
    container_name: db-mongo
    expose:
        - '27017'
    ports:
        - '27017:27017'
    networks:
        - default
    command: --nojournal

Both containers are residing on the same network - the Orion Context Broker is listening on Port 1026 and MongoDB is listening on the default port 27071. Both containers are also exposing the same ports externally - this is purely for the tutorial access - so that cUrl or Postman can access them without being part of the same network. The command-line initialization should be self-explanatory.

The only notable difference to the introductory tutorials is that the required image name is currently fiware/orion-ld.

Start Up

All services can be initialised from the command-line by running the services Bash script provided within the repository. Please clone the repository and create the necessary images by running the commands as shown:

git clone https://github.com/FIWARE/tutorials.Linked-Data.git
cd tutorials.Linked-Data
git checkout NGSI-v2

./services orion|scorpio|stellio

This command will also import seed data from the previous Store Finder tutorial on startup.

Note: If you want to clean up and start over again you can do so with the following command:

./services stop


Creating a "Powered by FIWARE" app based on Linked Data

This tutorial recreates the same data entities as the initial "Powered by FIWARE" supermarket finder app, but using NGSI-LD linked data entities rather than NGSI v2.

Checking the service health

As usual, you can check if the Orion Context Broker is running by making an HTTP request to the exposed port:

1️⃣ Request:

curl -X GET \
  'http://localhost:1026/version'

Response:

Tip: Use jq to format the JSON responses in this tutorial. Pipe the result by appending

| jq '.'

The response will look similar to the following:

{
    "orion": {
        "version": "1.15.0-next",
        "uptime": "0 d, 3 h, 1 m, 51 s",
        "git_hash": "af440c6e316075266094c2a5f3f4e4f8e3bb0668",
        "compile_time": "Tue Jul 16 15:46:18 UTC 2019",
        "compiled_by": "root",
        "compiled_in": "51b4d802385a",
        "release_date": "Tue Jul 16 15:46:18 UTC 2019",
        "doc": "https://fiware-orion.readthedocs.org/en/master/"
    }
}

The format of the version response has not changed. The release_date must be 16th July 2019 or later to be able to work with the requests defined below.

Creating Context Data

When creating linked data entities, it is important to use common data models. This will allow us to easily combine data from multiple sources and remove ambiguity when comparing data coming from different sources.

Creating linked data using fully qualified names throughout would be painful, as each attribute would need to be a URI, so JSON-LD introduces the idea of an @context attribute which can hold pointers to context definitions. To add a Smart Data Building data entity, the following @context would be required

{
    "id": "urn:ngsi-ld:Building:store001",
    "type": "Building",
    ...  other data attributes
    "@context": "https://smart-data-models.github.io/dataModel.Building/context.jsonld"

}

Core Context

https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld refers to the Core @context of NGSI-LD, this defines terms such as id and type which are common to all NGSI entities, as well as defining terms such as Property and Relationship. The core context is so fundamental to NGSI-LD, that it is added by default to any @context sent to a request.

Smart Data Models

https://smart-data-models.github.io/dataModel.Building/context.jsonld refers to a User @context - a definition of a standard data models. Adding this to the @context will load a common definition of a Building data model defined by the FIWARE Foundation in collaboration with other organizations such as GSMA or TM Forum. A summary of the FQNs related to Building can be seen below:

{
    "@context": {
        "Building": "https://smartdatamodels.org/dataModel.Building/Building",
        ... etc

        "address": "https://smartdatamodels.org/address",
        "addressCountry": "https://smartdatamodels.org/addressCountry",
        "addressLocality": "https://smartdatamodels.org/addressLocality",
        "addressRegion": "https://smartdatamodels.org/addressRegion",
        "category": "https://smartdatamodels.org/dataModel.Building/category",
        "name": "https://smartdatamodels.org/name",
        ...etc
    }
}

If we include this context definition, it means that we will be able to use short names for Building, address, name for our entities, but computers will also be able to read the FQNs when comparing with other sources.

Context terms are IRIs not URLs

It should be noted that According to the JSON-LD Spec : "a context is used to map terms to IRIs." - An IRI (Internationalized Resource Identifier) is not necessarily a URL - see here and therefore it is not unexpected if elements such as https://smartdatamodels.org/name do not actually resolve to a web page. However many IRIs within JSON-LD @context files, such as http://schema.org/address do indeed return web pages with more information about themselves.

If you take the NGSI-LD Core @context

{
  "@context": {

    "ngsi-ld": "https://uri.etsi.org/ngsi-ld/",
    "geojson": "https://purl.org/geojson/vocab#",
    "id": "@id",
    "type": "@type",
...
    "@vocab": "https://uri.etsi.org/ngsi-ld/default-context/"
  }
}

You can see that any unresolved short-name for an attribute will be mapped onto the default context i.e.:

  • Unknown attribute xxx => https://uri.etsi.org/ngsi-ld/default-context/xxx

And unsurprisingly these default-context IRIs don't exist as valid web pages either.

To create a valid Building data entity in the context broker, make a POST request to the http://localhost:1026/ngsi-ld/v1/entities endpoint as shown below. It is essential that the appropriate Content-Type: application/ld+json is also used, so that the data entity is recognized as Linked data.

2️⃣ Request:

curl -iX POST \
  'http://localhost:1026/ngsi-ld/v1/entities' \
  -H 'Content-Type: application/ld+json' \
  -d '{
    "id": "urn:ngsi-ld:Building:store001",
    "type": "Building",
    "category": {
        "type": "VocabularyProperty",
        "vocab": "commercial"
    },
    "address": {
        "type": "Property",
        "value": {
            "streetAddress": "Bornholmer Straße 65",
            "addressRegion": "Berlin",
            "addressLocality": "Prenzlauer Berg",
            "postalCode": "10439"
        },
        "verified": {
            "type": "Property",
            "value": true
        }
    },
    "location": {
        "type": "GeoProperty",
        "value": {
             "type": "Point",
             "coordinates": [13.3986, 52.5547]
        }
    },
    "name": {
        "type": "Property",
        "value": "Bösebrücke Einkauf"
    },
    "@context": [
        "https://smart-data-models.github.io/dataModel.Building/context.jsonld",
        "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld"
    ]
}'

The first request will take some time, as the context broker must navigate and load all of the files mentioned in the @context.

[!NOTE]

if https://smart-data-models.github.io/dataModel.Building/context.jsonld is unavailable for some reason the request will fail

For a working production system it is essential that the @context files are always available to ensure third parties can read the context. High availability infrastructure has not been considered for this tutorial to keep the architecture simple.

3️⃣ Request:

Each subsequent entity must have a unique id for the given type

curl -iX POST \
  http://localhost:1026/ngsi-ld/v1/entities/ \
  -H 'Content-Type: application/ld+json' \
  -d '{
    "id": "urn:ngsi-ld:Building:store002",
    "type": "Building",
    "category": {
        "type": "VocabularyProperty",
        "vocab": "commercial"
    },
    "address": {
        "type": "Property",
        "value": {
            "streetAddress": "Friedrichstraße 44",
            "addressRegion": "Berlin",
            "addressLocality": "Kreuzberg",
            "postalCode": "10969"
        },
        "verified": {
            "type": "Property",
            "value": true
        }
    },
     "location": {
        "type": "GeoProperty",
        "value": {
             "type": "Point",
              "coordinates": [13.3903, 52.5075]
        }
    },
    "name": {
        "type": "Property",
        "value": "Checkpoint Markt"
    },
    "@context": [
        "https://smart-data-models.github.io/dataModel.Building/context.jsonld",
        "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld"
    ]
}'

Defining Properties within the NGSI-LD entity definition

The attributes id and type should be familiar to anyone who has used NGSI v2, and these have not changed. As mentioned above, the type should refer to an included data model, in this case Building is being used as a short name for the included URN https://uri.fiware.org/ns/dataModels#Building. Thereafter each property is defined as a JSON element containing two attributes, a type and a value.

The type of a property attribute must be one of the following:

  • "GeoProperty": "http://uri.etsi.org/ngsi-ld/GeoProperty" for locations. Locations should be specified as Longitude-Latitude pairs in GeoJSON format. The preferred name for the primary location attribute is location
  • "VocabularyProperty" holds enumerated values and is a mapping of a URI to a value within the user'@context
  • "LanguageProperty" holds a set of internationalized strings.
  • "Property": "http://uri.etsi.org/ngsi-ld/Property" - for everything else.
  • For time-based values, "Property" shall be used as well, but the property value should be Date, Time or DateTime strings encoded in the ISO 8601 format - e.g. YYYY-MM-DDThh:mm:ssZ

[!NOTE]

Note that for simplicity, this data entity has no relationships defined. Relationships must be given the type=Relationship or one of its defined subtypes. Relationships will be discussed in a subsequent tutorial.

Defining Properties-of-Properties within the NGSI-LD entity definition

Properties-of-Properties is the NGSI-LD equivalent of metadata (i.e. "data about data"), it is use to describe properties of the attribute value itself like accuracy, provider, or the units to be used. Some built-in metadata attributes already exist and these names are reserved:

  • createdAt (type: DateTime): attribute creation date as an ISO 8601 string.
  • modifiedAt (type: DateTime): attribute modification date as an ISO 8601 string.

Additionally observedAt, datasetId and instanceId may optionally be added in some cases, and location, observationSpace and operationSpace have special meaning for Geoproperties.

In the examples given above, one element of metadata (i.e. a property-of-a-property) can be found within the address attribute. a verified flag indicates whether the address has been confirmed. The commonest property-of-a-property is unitCode which should be used to hold the UN/CEFACT Common Codes for Units of Measurement.

A valueType property-of-a-property can be used to describe the Datatype of an attribute.

  • For Native JSON Properties, the valueType can align with a well-known Datatype schema, such as schema.org or XML Schema - typically values such as: Time, Boolean, DateTime, Number, Text, Date, Float, Integer etc.
  • For other JSON Objects, where possible use a datatype from an existing ontology - for example PostalAddress aligns with https://schema.org/PostalAddress.

When using valueType , the mapping of the given short name value to a full URI should be placed in the User @context

Querying Context Data

A consuming application can now request context data by making NGSI-LD HTTP requests to the Orion Context Broker. The existing NGSI-LD interface enables us to make complex queries and filter results and retrieve data with FQNs or with short names.

Obtain entity data by FQN Type

This example returns the data of all Building entities within the context data The type parameter is mandatory for NGSI-LD and is used to filter the response. The Accept HTTP header is needed to retrieve JSON-LD content.

4️⃣ Request:

curl -G -X GET \
  'http://localhost:1026/ngsi-ld/v1/entities' \
  -H 'Accept: application/ld+json' \
  -d 'type=https%3A%2F%2Fsmartdatamodels.org%2FdataModel.Building%2FBuilding'

Response:

The response returns the Core @context by default (https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld) and all attributes are expanded whenever possible.

  • id, type and location are defined in the core context and are not expanded.
  • address has been mapped to http://smartdatamodels.org/address
  • name has been mapped to http://smartdatamodels.org/name
  • category has been mapped to https://smartdatamodels.org/dataModel.Building/category

Note that if an attribute has not been not associated to an FQN when the entity was created, the short name will always be displayed - verified and commercial are examples of this since they were missing from the supplied user @context when inserting the context data.

[
    {
        "@context": "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld",
        "id": "urn:ngsi-ld:Building:store001",
        "type": "https://smartdatamodels.org/dataModel.Building/Building",
        "https://smartdatamodels.org/dataModel.Building/category": {
            "type": "VocabularyProperty",
            "vocab": "commercial"
        },
        "https://smartdatamodels.org/address": {
            "type": "Property",
            "value": {
                "https://smartdatamodels.org/streetAddress": "Bornholmer Straße 65",
                "https://smartdatamodels.org/addressRegion": "Berlin",
                "https://smartdatamodels.org/addressLocality": "Prenzlauer Berg",
                "https://smartdatamodels.org/postalCode": "10439"
            },
            "verified": {
                "type": "Property",
                "value": true
            }
        },
        "location": {
            "type": "GeoProperty",
            "value": {
                "type": "Point",
                "coordinates": [13.3986, 52.5547]
            }
        },
        "https://smartdatamodels.org/name": {
            "type": "Property",
            "value": "Bösebrücke Einkauf"
        }
    },
    {
        "@context": "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld",
        "id": "urn:ngsi-ld:Building:store002",
        "type": "https://smartdatamodels.org/dataModel.Building/Building",
        "https://smartdatamodels.org/dataModel.Building/category": {
            "type": "VocabularyProperty",
            "vocab": "commercial"
        },
        "https://smartdatamodels.org/address": {
            "type": "Property",
            "value": {
                "https://smartdatamodels.org/streetAddress": "Friedrichstraße 44",
                "https://smartdatamodels.org/addressRegion": "Berlin",
                "https://smartdatamodels.org/addressLocality": "Kreuzberg",
                "https://smartdatamodels.org/postalCode": "10969"
            },
            "verified": {
                "type": "Property",
                "value": true
            }
        },
        "location": {
            "type": "GeoProperty",
            "value": {
                "type": "Point",
                "coordinates": [13.3903, 52.5075]
            }
        },
        "https://smartdatamodels.org/name": {
            "type": "Property",
            "value": "Checkpoint Markt"
        }
    }
]

Obtain entity data by ID

This example returns the data of urn:ngsi-ld:Building:store001

5️⃣ Request:

curl -G -X GET \
   -H 'Accept: application/ld+json' \
   'http://localhost:1026/ngsi-ld/v1/entities/urn:ngsi-ld:Building:store001'

Response:

The response returns the Core @context by default (https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld) and all attributes are expanded whenever possible.

{
    "@context": "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld",
    "id": "urn:ngsi-ld:Building:store001",
    "type": "https://smartdatamodels.org/dataModel.Building/Building",
    "https://smartdatamodels.org/dataModel.Building/category": {
        "type": "VocabularyProperty",
        "vocab": "commercial"
    },
    "https://smartdatamodels.org/address": {
        "https://smartdatamodels.org/streetAddress": "Bornholmer Straße 65",
        "https://smartdatamodels.org/addressRegion": "Berlin",
        "https://smartdatamodels.org/addressLocality": "Prenzlauer Berg",
        "https://smartdatamodels.org/postalCode": "10439"
    },
    "location": {
        "type": "Point",
        "coordinates": [13.3986, 52.5547]
    },
    "https://smartdatamodels.org/name": "Bösebrücke Einkauf"
}

Obtain entity data by type

If a reference to the supplied data is supplied, it is possible to return short name data and limit responses to a specific type of data. For example, the request below returns the data of all Building entities within the context data. Use of the type parameter limits the response to Building entities only, use of the options=keyValues query parameter reduces the response down to standard JSON-LD.

A Link header must be supplied to associate the short form type="Building" with the FQN https://uri.fiware.org/ns/data-models/Building. The full link header syntax can be seen below:

Link: <https://smart-data-models.github.io/dataModel.Building/context.jsonld>; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json

The standard HTTP Link header allows metadata (in this case the @context) to be passed in without actually touching the resource in question. In the case of NGSI-LD, the metadata is a file in application/ld+json format.

6️⃣ Request:

curl -G -X GET \
  'http://localhost:1026/ngsi-ld/v1/entities' \
    -H 'Link: <https://smart-data-models.github.io/dataModel.Building/context.jsonld>; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json"' \
    -H 'Accept: application/ld+json' \
    -d 'type=Building' \
    -d 'options=keyValues'

Response:

Because of the use of the options=keyValues, the response consists of JSON only without the attribute definitions type="Property" or any properties-of-properties elements. You can see that Link header from the request has been used as the @context returned in the response.

[
    {
        "@context": [
            "https://smart-data-models.github.io/dataModel.Building/context.jsonld",
            "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld"
        ],
        "id": "urn:ngsi-ld:Building:store001",
        "type": "Building",
        "address": {
            "streetAddress": "Bornholmer Straße 65",
            "addressRegion": "Berlin",
            "addressLocality": "Prenzlauer Berg",
            "postalCode": "10439"
        },
        "name": "Bösebrücke Einkauf",
        "category": {
            "vocab": "commercial"
        },
        "location": {
            "type": "Point",
            "coordinates": [13.3986, 52.5547]
        }
    },
    {
        "@context": [
            "https://smart-data-models.github.io/dataModel.Building/context.jsonld",
            "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld"
        ],
        "id": "urn:ngsi-ld:Building:store002",
        "type": "Building",
        "address": {
            "streetAddress": "Friedrichstraße 44",
            "addressRegion": "Berlin",
            "addressLocality": "Kreuzberg",
            "postalCode": "10969"
        },
        "name": "Checkpoint Markt",
        "category": {
            "vocab": "commercial"
        },
        "location": {
            "type": "Point",
            "coordinates": [13.3903, 52.5075]
        }
    }
]

Filter context data by comparing the values of an attribute

This example returns all Building entities with the name attribute Checkpoint Markt. Filtering can be done using the q parameter - if a string has spaces in it, it can be URL encoded and held within double quote characters " = %22.

7️⃣ Request:

curl -G -X GET \
    'http://localhost:1026/ngsi-ld/v1/entities' \
    -H 'Link: <https://smart-data-models.github.io/dataModel.Building/context.jsonld>; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json"' \
    -H 'Accept: application/ld+json' \
    -d 'type=Building' \
    -d 'q=name==%22Checkpoint%20Markt%22' \
    -d 'options=keyValues'

Response:

The Link header https://smart-data-models.github.io/dataModel.Building/context.jsonld includes the FIWARE Building model.

This means that use of the Link header and the options=keyValues parameter reduces the response to short form JSON-LD as shown:

[
    {
        "@context": [
            "https://smart-data-models.github.io/dataModel.Building/context.jsonld",
            "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld"
        ],
        "id": "urn:ngsi-ld:Building:store002",
        "type": "Building",
        "address": {
            "streetAddress": "Friedrichstraße 44",
            "addressRegion": "Berlin",
            "addressLocality": "Kreuzberg",
            "postalCode": "10969"
        },
        "name": "Checkpoint Markt",
        "category": {
            "vocab": "commercial"
        },
        "location": {
            "type": "Point",
            "coordinates": [13.3903, 52.5075]
        }
    }
]

Filter context data by comparing the values of an attribute in an Array

Within the standard Building model, the category attribute refers to an array of enumerated strings. This example returns all Building entities with a category attribute which contains either commercial or office strings. Filtering can be done using the q parameter, comma separating the acceptable values.

[!NOTE]

category has been defined as a VocabularyProperty, which would usually mean that the vocab value should be a URI defined in the @context. The expandValues hint indicates that URI expansion is required for the category attribute when querying the context data.

8️⃣ Request:

curl -G -X GET \
    'http://localhost:1026/ngsi-ld/v1/entities' \
    -H 'Link: <https://smart-data-models.github.io/dataModel.Building/context.jsonld>; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json"' \
    -H 'Accept: application/ld+json' \
    -d 'type=Building' \
    -d 'q=category==%22commercial%22,%22office%22' \
    -d 'options=keyValues' \
    -d 'expandValues=category'

Response:

The response is returned in JSON-LD format with short form attribute names:

[
    {
        "@context": [
            "https://smart-data-models.github.io/dataModel.Building/context.jsonld",
            "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld"
        ],
        "id": "urn:ngsi-ld:Building:store001",
        "type": "Building",
        "address": {
            "streetAddress": "Bornholmer Straße 65",
            "addressRegion": "Berlin",
            "addressLocality": "Prenzlauer Berg",
            "postalCode": "10439"
        },
        "name": "Bösebrücke Einkauf",
        "category": {
            "vocab": "commercial"
        },
        "location": {
            "type": "Point",
            "coordinates": [13.3986, 52.5547]
        }
    },
    {
        "@context": [
            "https://smart-data-models.github.io/dataModel.Building/context.jsonld",
            "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld"
        ],
        "id": "urn:ngsi-ld:Building:store002",
        "type": "Building",
        "address": {
            "streetAddress": "Friedrichstraße 44",
            "addressRegion": "Berlin",
            "addressLocality": "Kreuzberg",
            "postalCode": "10969"
        },
        "name": "Checkpoint Markt",
        "category": {
            "vocab": "commercial"
        },
        "location": {
            "type": "Point",
            "coordinates": [13.3903, 52.5075]
        }
    }
]

Filter context data by comparing the values of a sub-attribute

This example returns all stores found in the Kreuzberg District.

Filtering can be done using the q parameter - sub-attributes are annotated using the bracket syntax e.g. q=address[addressLocality]=="Kreuzberg". This differs from NGSI v2 where dot syntax was used.

9️⃣ Request:

curl -G -X GET \
    'http://localhost:1026/ngsi-ld/v1/entities' \
    -H 'Link: <https://smart-data-models.github.io/dataModel.Building/context.jsonld>; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json"' \
    -H 'Accept: application/ld+json' \
    -d 'type=Building' \
    -d 'q=address%5BaddressLocality%5D==%22Kreuzberg%22' \
    -d 'options=keyValues'

Response:

Use of the Link header and the options=keyValues parameter reduces the response to JSON-LD.

[
    {
        "@context": [
            "https://smart-data-models.github.io/dataModel.Building/context.jsonld",
            "https://uri.etsi.org/ngsi-ld/v1/ngsi-ld-core-context-v1.6.jsonld"
        ],
        "id": "urn:ngsi-ld:Building:store002",
        "type": "Building",
        "address": {
            "streetAddress": "Friedrichstraße 44",
            "addressRegion": "Berlin",
            "addressLocality": "Kreuzberg",
            "postalCode": "10969"
        },
        "name": "Checkpoint Markt",
        "category": {
            "vocab": "commercial"
        },
        "location": {
            "type": "Point",
            "coordinates": [13.3903, 52.5075]
        }
    }
]

Filter context data by querying metadata

This example returns the data of all Building entities with a verified address. The verified attribute is an example of a Property-of-a-Property

Metadata queries (i.e. Properties of Properties) are annotated using the dot syntax e.g. q=address.verified==true. This supersedes the mq parameter from NGSI v2.

1️⃣0️⃣ Request:

curl -G -X GET \
    'http://localhost:1026/ngsi-ld/v1/entities' \
    -H 'Link: <https://smart-data-models.github.io/dataModel.Building/context.jsonld>; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json"' \
    -H 'Accept: application/json' \
    -d 'type=Building' \
    -d 'q=address.verified==true' \
    -d 'options=keyValues'

Response:

Because of the use of the options=keyValues together with the Accept HTTP header (application/json), the response consists of JSON only without the attribute type and metadata elements.

[
    {
       "id": "urn:ngsi-ld:Building:store001",
        "type": "Building",
        "address": {
            "streetAddress": "Bornholmer Straße 65",
            "addressRegion": "Berlin",
            "addressLocality": "Prenzlauer Berg",
            "postalCode": "10439"
        },
        "name": "Bösebrücke Einkauf",
        "category": {
            "vocab": "commercial"
        },
        "location": {
            "type": "Point",
            "coordinates": [13.3986, 52.5547]
        }
    },
    {
        "id": "urn:ngsi-ld:Building:store002",
        "type": "Building",
        "address": {
            "streetAddress": "Friedrichstraße 44",
            "addressRegion": "Berlin",
            "addressLocality": "Kreuzberg",
            "postalCode": "10969"
        },
        "name": "Checkpoint Markt",
        "category": {
            "vocab": "commercial"
        },
        "location": {
            "type": "Point",
            "coordinates": [13.3903, 52.5075]
        }
    }
]

Filter context data by comparing the values of a geo:json attribute

This example return all Stores within 2km the Brandenburg Gate in Berlin (52.5162N 13.3777W). To make a geo-query request, three parameters must be specified, geometry, coordinates and georel.

The syntax for NGSI-LD has been updated, the coordinates parameter is now represented in geoJSON including the square brackets rather than the simple lat-long pairs required in NGSI v2.

Note that by default the geo-query will be applied to the location attribute, as this is default specified in NGSI-LD. If another attribute is to be used, an additional geoproperty parameter is required.

1️⃣1️⃣ Request:

curl -G -X GET \
  'http://localhost:1026/ngsi-ld/v1/entities' \
  -H 'Link: <https://smart-data-models.github.io/dataModel.Building/context.jsonld>; rel="http://www.w3.org/ns/json-ld#context"; type="application/ld+json"' \
  -H 'Accept: application/json' \
  -d 'type=Building' \
  -d 'geometry=Point' \
  -d 'coordinates=%5B13.3777,52.5162%5D' \
  -d 'georel=near%3BmaxDistance==2000' \
  -d 'options=keyValues'

Response:

Because of the use of the options=keyValues together with the Accept HTTP header (application/json), the response consists of JSON only without the attribute type and metadata elements.

[
    {
        "id": "urn:ngsi-ld:Building:store002",
        "type": "Building",
        "address": {
            "streetAddress": "Friedrichstraße 44",
            "addressRegion": "Berlin",
            "addressLocality": "Kreuzberg",
            "postalCode": "10969"
        },
        "name": "Checkpoint Markt",
        "category": {
            "vocab": "commercial"
        },
        "location": {
            "type": "Point",
            "coordinates": [13.3903, 52.5075]
        }
    }
]