Every schema defines an entity. The type of the entity is specified in
the valueType
of the root node of the layer. An entity may have a
unique identifier. The unique identifier contains one or more
attributes. These attribute must not be included in array fields.
Below is a schema for a https://example.org/Person
whose ID field is
https://example/org/Person/id
:
{
"@context": "https://layeredschemas.org/ls.json",
"@id": "http://example.org/Person/schemaBase",
"@type": "Schema",
"valueType": "https://example.org/Person",
"layer": {
"@type": "Object",
"@id": "http://example.org/Person",
"entityIdFields": "https://example.org/Person/id",
"attributes": [
{
"@id": "http://example.org/Person/firstName",
"@type": "Value",
"attributeName":"firstName"
},
{
"@id": "http://example.org/Person/lastName",
"@type": "Value",
"attributeName": "lastName"
},
{
"@id": "http://example.org/Person/id",
"@type": "Value",
"attributeName": "id"
},
{
"@id": "http://example.org/Person/contact",
"@type": "Array",
"attributeName": "contact",
"arrayElements": {
"@type": "Reference",
"@id": "http://example.org/Person/contact/items",
"ref": "https://example.org/Contact"
}
}
]
}
}
When a schema is compiled. the entity root nodes are marked with
https://lschema.org/entitySchema
term that gives the schema ID for
the entity. The following graph shows the compiled schema for
https://example.org/Person
entity. The root nodes for Person
and
Contact
entities are marked with https://lschema.org/entitySchema
annotation showing the schema for those entities. The Person
entity
also declares the https://example.org/Person/id
field as an entity
id. All the attributes under the Person
root node up until the
Contact
root node belong to the Person
object. All the attributes
under the Contact
root node belong to the Contact
object.
When data elements are ingested, all nodes that are instances of
entity root nodes with nonempty entityIdFields
annotation will have
the https://lschema.org/entityId
field initialized to the entity
ID. If the entityIdFields
is string value, then entityId
will be
initialized to the content of that attribute. If entityIfFields
is an
array, the entityId
will be initialized as an array where every
element initialized from the value of the corresponding ID field.
A schema may specify the creation of additional links between ingested
entities. Consider the following entity named A
:
{
"@context": "https://layeredschemas.org/ls.json",
"@id": "http://example.org/A/schema",
"@type": "Schema",
"valueType": "https://example.org/A",
"layer": {
"@type": "Object",
"@id": "http://example.org/A",
"entityIdFields": "http://example.org/A/id",
"attributes": {
"http://example.org/A/id": {
"@type": "Value",
"attributeName": "id"
}
}
}
}
Here is another entity B
that contains a foreign key containing the
identifier for an A
entity:
{
"@context": "https://layeredschemas.org/ls.json",
"@id": "http://example.org/B/schema",
"@type": "Schema",
"valueType": "https://example.org/B",
"layer": {
"@type": "Object",
"@id": "http://example.org/B",
"attributes": {
"https://example.org/B/a_id": {
"@type": "Value",
"attributeName": "a_id"
}
}
}
}
When instances of A
and B
are ingested, we would like to create a
link from the A
instance to its B
instance. The following addition
to the B
schema does this:
{
"@context": "https://layeredschemas.org/ls.json",
"@id": "http://example.org/B/schema",
"@type": "Schema",
"valueType": "https://example.org/B",
"layer": {
"@type": "Object",
"@id": "http://example.org/B",
"attributes": {
"https://example.org/B/a_id": {
"@type": "Value",
"attributeName": "a_id"
},
"http://example.org/B/owner": {
"@type": "Reference",
"reference": "https://example.org/A/schema",
"fk": "https://example.org/B/a_id",
"link": "to",
"ingestAs": "edge",
"label": "owner",
"multi": false
}
}
}
}
Here, the owner
field defines a reference to A
using its schema
ID. The other fields define how the link is constructed, and how the
A
instance is found:
fk
specifies the foreign key field contained in B
that
contains the A
entity id. If the A
entity has multiple
identifiers, the fk
field must specify an array of fields.link
specifies the link direction. If to
, the link is from A
to B
. If from
, the link is from B
to A
.ingestAs
specifies how the link should be established. If
edge
, an edge is added between the root node of B
and the root
node of A
. If node
, a node is created for the owner
field,
and that node is connected to the root node of A
.label
specifies the edge label. If omitted,
https://lschema.org/has
is used.multi
is true
and there are multiple instances of A
with the
given identifier, the B
entity is linked to all those matching
A
entities. If multi
is false and multiple A
entities match,
an error is returned.The resulting graph is:
An alternative method of linking uses foreign-key attributes directly. This form of linking entities is useful for database operations where the linked entity may not yet exist. This form stores the linking related annotations as part of the foreign key so they can later be used to conntect related objects in a database.
{
"@context": "https://layeredschemas.org/ls.json",
"@id": "http://example.org/B/schema",
"@type": "Schema",
"valueType": "https://example.org/B",
"layer": {
"@type": "Object",
"@id": "http://example.org/B",
"attributes": {
"https://example.org/B/a_id": {
"@type": "Value",
"attributeName": "a_id",
"reference": "https://example.org/A/schema",
"link": "to",
"linkNode": "https://example.org/B",
"label": "owner",
"multi": false
}
}
}
}
In this form, the linking annotations are directly added to one of the
foreign-key attributes. A missing fk
annotation means the attribute
itself is the foreign key. If the linked object has a composite key,
then one of the foreign key attributes can be used and a fk
must be
specified to include all foreign key fields. The linkNode
annotation
specifies the node that will be connected to the other entity, which
must be the schema node ID that must be one of the ancestors of the
foreign key node. In this example, the connection will be from the
entity root node of A
to the entity root node of B
.