Linked entities
Add join to a query and Andromeda follows Relationships for you. It fetches the entities they point at, either appended to the answer (flat) or nested under each Relationship (inline). pick and omit decide which attributes of those linked entities you get.
Joining
A Relationship's target is a linked entity. With join, Andromeda retrieves linked entities together with the entities you asked for:
GET /ngsi-ld/v1/entities?type=Car&join=flat&joinLevel=1&pick=id,type,owner,name
[
{
"id": "urn:ngsi-ld:Car:1",
"type": "Car",
"owner": {
"type": "Relationship",
"object": "urn:ngsi-ld:Person:7"
}
},
{
"id": "urn:ngsi-ld:Person:7",
"type": "Person",
"name": {
"type": "Property",
"value": "Ana"
}
}
]
join=flatappends each linked entity to the answer once, next to the entities you asked for.join=inlineputs a copy of the linked entity under the Relationship that points at it, asentity(orentityListfor a ListRelationship).join=@none, or nojoinat all, retrieves no linked entities.
joinLevel is how many Relationship hops to follow. Andromeda sets no maximum. containedBy lists entity identifiers you have already seen. Andromeda doesn't fetch those again. It only works together with joinLevel, and has no effect without it.
Linked entities are fetched breadth first, one level at a time, local entities before those held by context sources.
Narrowing linked entities
A linked entity term names an attribute of a linked entity. pick=owner{name} keeps owner, and keeps only name in the entity owner points at. In q, a hop such as q=owner{age}>30 filters on the linked entity. omit=owner{age} keeps owner and takes age out of its target.
Andromeda only reaches a linked entity through an attribute your list returns. With omit=owner, nothing is fetched through owner.
What narrows the linked entity itself depends on whether your list has a linked entity term in it.
Without one, the list applies to every entity in the answer. pick=name,owner with join=flat returns every linked entity narrowed to name and owner as well.
With one, each part of the list applies to the entity it was written for. The target of owner{name} is narrowed to name. The target of a Relationship you list without a group comes back whole. A group applies only to the entity it names, not to entities reached from that one in turn.
If the list leaves a linked entity empty, it isn't written at all. Inline writes no entity for it, and flat doesn't append it. The Relationship keeps its object, and the empty entity's own Relationships aren't followed.
attrs (and notification.attributes) is a synonym for pick that doesn't allow id, type and scope. Like a pick that doesn't name it, it drops scope. The temporal query is the exception, because there the Scope is a reified Property that attrs can name.
Where linked entity terms work
| Operation | Linked entity terms |
|---|---|
| Retrieve Entity | pick and omit work with join and within joinLevel; q doesn't apply |
| Query Entities, and an EntityMap for Query Entities | pick and omit, and hops in q, work with join and within joinLevel |
| Purge Entities | refused, in pick, omit and q |
| Temporal retrieval and query | refused, unless the temporal_linked_retrieval extension is on |
| Create and Update Subscription | accepted in pick, omit and q, with or without a join |
A term or hop deeper than joinLevel, or used without join, gets 400 BadRequestData. A chain of hops in q counts against the depth a q path may walk (see Andromeda's own bounds).
A subscription takes linked entity terms even without notification.join. Without a join, pick=["owner{name}"] keeps owner, and the group has nothing to apply to. Andromeda stores the terms and returns them as you wrote them. A malformed term is still refused.
Flat: each linked entity once
join=flat appends a linked entity once, however many Relationships reach it. The first time it is reached decides which list narrows it. Andromeda goes:
- level by level
- within a level, entity by entity in the order of the answer
- within an entity, attribute by attribute in the order your
pickorattrsnames them, or else the order they are stored in - through instances,
objectarrays andobjectListmembers in order
Inline: a copy under every Relationship
join=inline puts a copy under every Relationship instance that reaches the linked entity, each narrowed by the list along its own path. A target that is already open on the current path, or listed in containedBy, stays a plain URI. That stops loops. It doesn't remove repeats elsewhere in the answer.
Linked entities from context sources
A linked entity stored locally is joined whether or not its Relationship carries objectType. One that Andromeda doesn't hold is fetched from a context source only when its Relationship carries objectType.
If a linked entity can't be retrieved, an HTTP answer says so in an NGSILD-Warning header. A notification is delivered without it.
Notifications
Notifications get the same linked entity retrieval as queries. That covers both join modes, notification.joinLevel, linked entity terms, plain pick and omit, notification.attributes, and linked entities from context sources (unless the subscription is localOnly). A subscription can't use containedBy. A notification about a deleted entity retrieves no linked entities.
Temporal API
The Temporal API has no linked entity retrieval. A projection or filter that uses it is refused, and join, joinLevel and containedBy aren't parameters of the temporal operations. That is what you get by default. The temporal linked retrieval extension applies the rules on this page to temporal retrieval and queries, over the request's time window.
Where Andromeda interprets the specification
Linked entity retrieval and projection are defined by the specification. It sets no maximum joinLevel, and neither does Andromeda. containedBy is tied to joinLevel. Terms without join or beyond joinLevel are refused. Nothing gives subscriptions an admission rule for linked entity terms, so Andromeda accepts them.
A list without linked entity terms "applies to all Entities in the payload in the case of Linked Entity retrieval". The attrs synonym and its limits come from the parameter tables.
Flat appends each target once, "unless a target URI has been previously encountered". For inline, a linked entity is nested "unless a URI has been previously encountered". Andromeda reads that as loop protection, not as removing repeats across the whole answer.