Relationships
Introduction
In MongoDB, documents can have relationships with other documents (see MongoDB Relationships documentation section).
RESTHeart allows to declare the existing relationships in a collection, so that it automatically adds the links to related documents in its representation.
Declaring relationships adds the _links
property to the documents only in the HAL representation format. This is not available in the default representation format. Add the query parameters ?rep=HAL&hal=f
to display the _links
property.
The rels collection metadata
In RESTHeart, not only documents but also dbs and collections have properties. Some properties are metadata, i.e. they have a special meaning for RESTheart that influences its behavior.
The collection metadata rels
allows to declare existing
relationship so that links to the referenced documents are auto-magically included in the _link
property
rels
is an array of rel
objects having the following format:
{
"rel": "<relid>",
"type": "<type>",
"role": "<role>",
"target-db": "<dname>",
"target-coll": "<collname>",
"ref-field": "<reffieldname>"
}
Property
|
Description
|
Mandatory
|
---|---|---|
rel |
Name of the relationship. |
Yes |
type |
Type of relationship: ONE_TO_ONE, MANY_TO_ONE, ONE_TO_MANY or MANY_TO_MANY | Yes |
role |
Role of the relationship: OWNING or INVERSE. This says where the reference field is. OWNING means it is in this document, INVERSE means that it is on the target document. | Yes |
target-db |
Database name of the referenced document(s) | No. If omitted the target db is supposed to be the current one |
target-coll |
Collection's name of the referenced document(s) | Yes |
ref-field |
Name of the first level field storing the id(s) of the referenced document(s) or the json path expression that resolves to the ids of the referenced documents (to reference nested fields). The value of the first level field must be either the id string (in case the multiplicity of other side of the relationship is ONE) or an array of id strings (in case the multiplicity of other side of the relationship is MANY) Note: json path expression must start with
|
Yes |
Examples
Tree of documents
In this example, we create a collection to store documents organized in a tree (each document has a single parent document).
Let’s create a collection, declaring a many-to-one relationship
called parent
, so that documents can refer a parent document in
the collection itself.
PUT /parentcoll HTTP/1.1
{
"rels": [
{
"rel": "parent",
"type": "MANY_TO_ONE",
"role": "OWNING",
"target-coll": "parentcoll",
"ref-field": "parent"
}
]
}
HTTP/1.1 201 CREATED
Let’s now create few documents, specifying the parent
property:
PUT /parentcoll/root HTTP/1.1
{"parent":"root"}
HTTP/1.1 201 CREATED
PUT /parentcoll/1 HTTP/1.1
{"parent":"root"}
HTTP/1.1 201 CREATED
PUT /parentcoll/1.1 HTTP/1.1
{"parent":"1"}
HTTP/1.1 201 CREATED
PUT /parentcoll/1.2 HTTP/1.1
{"parent":"1"}
HTTP/1.1 201 CREATED
If we now get the document /parentcoll/1.2
, the _links
property
includes parent
with the correct URI of the
document /parentcoll/1
GET /test/parentcoll/1.2 HTTP/1.1
HTTP/1.1 200 OK
{
"_id": "1.2",
"parent": 1,
"_links": {
"parent": {
"href": "/parentcoll/1"
}
}
}
One-to-Many, owning
In this example, we create two collections: bands
and albums
; of
course, each band has a 1:N relationship to albums.
PUT /bands HTTP/1.1
{
"rels": [{
"rel": "albums",
"type": "ONE_TO_MANY",
"role": "OWNING",
"target-coll": "albums",
"ref-field": "albums"
}],
"descr": "music bands"
}
HTTP/1.1 201 CREATED
PUT /albums HTTP/1.1
{ "descr":"albums published by music bands" }
HTTP/1.1 201 CREATED
Let’s now create few albums:
PUT /albums/Disintegration HTTP/1.1
{"year":1989}
HTTP/1.1 201 CREATED
PUT /albums/Wish HTTP/1.1
{"year":1992}
HTTP/1.1 201 CREATED
PUT /albums/Bloodflowers HTTP/1.1
{"year":2000}
HTTP/1.1 201 CREATED
Now we create the band referring these albums:
PUT /bands/The%20Cure HTTP/1.1
{"albums":["Disintegration","Wish","Bloodflowers"]}
HTTP/1.1 201 CREATED
If we now get The Cure document, we can notice the albums
link: /albums?filter={'_id':{'$in':['Disintegration','Wish','Bloodflowers']}}"
Since the other side of the relationship has cardinality N, the albums
link is a collection resource URI with a filter query parameter.
GET /bands/The%20Cure HTTP/1.1
HTTP/1.1 200 OK
{
"_id": "The Cure",
"_links": {
"albums": {
"href": "/albums?filter={'_id':{'$in':['Disintegration','Wish','Bloodflowers']}}"
},
},
"albums": [
"Disintegration",
"Wish",
"Bloodflowers"
]
}
If we want to get the referenced document with httpie (or curl) we need to issue the following request:
GET /albums?filter="{'_id':{'$in':['Disintegration','Wish','Bloodflowers']}}"` HTTP/1.1
One-to-Many, inverse
We’ll resemble the previous example, but using an inverse relationship, i.e. the field storing the relationship will be stored in the album documents.
PUT /bandsi HTTP/1.1
{
"rels": [
{
"rel": "albums",
"type": "ONE_TO_MANY",
"role": "INVERSE",
"target-coll": "albums",
"ref-field": "band"
}
],
"descr": "music bands"
}
HTTP/1.1 201 CREATED
PUT /albumsi HTTP/1.1
{ "descr":"albums published by music bands" }
HTTP/1.1 201 CREATED
Let’s now create few albums:
PUT /albumsi/Disintegration HTTP/1.1
{ "year":1989, "band":"The Cure" }
HTTP/1.1 201 CREATED
PUT /albumsi/Wish HTTP/1.1
{ "year":1992, "band":"The Cure" }
HTTP/1.1 201 CREATED
PUT /test/albumsi/Bloodflowers HTTP/1.1
{ "year":2000, "band":"The Cure" }
HTTP/1.1 201 CREATED
Now we create the band referred by these albums:
PUT /bandsi/The%20Cure HTTP/1.1
{"descr":"The Cure are an English rock band formed in Crawley, West Sussex, in 1976"}
HTTP/1.1 201 CREATED
If we now get “The Cure” document, we can notice the albums
link: /albumsi?filter={'band':'The Cure'}
GET /test/bandsi/The%20Cure HTTP/1.1
HTTP/1.1 200 OK
{
"_id": "The Cure",
"_links": {
"albums": {
"href": "/test/albums?filter={'band':'The Cure'}"
}
},
"descr": "The Cure are an English rock band formed in Crawley, West Sussex, in 1976"
}