# Multi-modelity
# General information
MamBase is a multi-model database which supports the following models:
- relational,
- graph,
- document.
In MamBase, it is possible to query data in any model using the query language that is the most natural and appropriate for that model. Relational data are queryable using SQL; graph data are queryable using the Gremlin-style Graph-It language.
All the models are "of equal rights" and are just representations ("views") of the internal MamBase model. The internal model is close to the graph one. It is possible to access the internal model directly using C++ API.
All the views are writeable and modifiable. Changes in any view force changes in the internal model and, hence, in other views.
# Graph view
The graph view most closely corresponds to the internal model. In the graph view, a fragment of the demo database looks like the below diagram:
For querying graph view, SPARQL and Graph-It can be used.
The SPARQL query below returns car number, year of manufacture, and owner name:
SELECT * {
[] type car ;
model ?model ;
year ?year ;
owner [ name ?dname ] .
}
The Graph-it language is a navigational language that is syntacticaly close to Gremlin:
g().v(car)
.in(type)
.get(model, year)
.out(owner).get(name)
.select(model, year, name)
Results of both the queries are the same:
+-------------+------+-------------+
| model | year | name |
+-------------+------+-------------+
| "Bugatti" | 2015 | "Brad" |
+-------------+------+-------------+
| "Mercedes" | 2014 | "Angelina" |
+-------------+------+-------------+
| "Mercedes" | 2014 | "Brad" |
+-------------+------+-------------+
| "Bentley" | 2016 | "Angelina" |
+-------------+------+-------------+
# Relational view
In relational view, the data are presented as four tables.
The 'person' table
id | name | lastname | age | city |
---|---|---|---|---|
"1234567801" | Brad | Pitt | 56 | Shawnee |
"1234567802" | Angelina | Jolie | 43 | Los Angeles |
The 'car' table
id | model | year | color | number |
---|---|---|---|---|
"1234567803" | Bugatti | 2015 | blue | US 1234 |
"1234567804" | Mercedes | 2014 | black | US 4444 |
"1234567805" | Bentley | 2016 | red | US 4321 |
The 'owner' table
fromid | toid |
---|---|
"1234567803" | "1234567001" |
"1234567804" | "1234567001" |
"1234567804" | "1234567002" |
"1234567805" | "1234567002" |
The 'friend' table
fromid | toid |
---|---|
1234567801 | 1234567002 |
The SQL query below returns car number, year of manufacture, and owner name:
SELECT с.model, с.year, p.name
FROM car с
JOIN owner o ON c.id = o.fromid
JOIN person p ON p.personid = o.toid
Moreover, it is possible to query the 'car' table as if it contains the 'owner' column referencing records in the 'person' table directly:
SELECT c.model, c.year, p.name
FROM car c
JOIN person p ON с.owner = p.id
Results of both the queries are the same:
+-------------+------+-------------+
| model | year | name |
+-------------+------+-------------+
| "Bugatti" | 2015 | "Brad" |
+-------------+------+-------------+
| "Mercedes" | 2014 | "Angelina" |
+-------------+------+-------------+
| "Mercedes" | 2014 | "Brad" |
+-------------+------+-------------+
| "Bentley" | 2016 | "Angelina" |
+-------------+------+-------------+
# JSON view
In the document model, the data will be represented as two collections:
The 'person' collection (2 documents)
{
"id" : "1234567801",
"type" : "person",
"name" : "Brad",
"lastname" : "Pitt",
"age" : 56,
"city" : "Shawnee"
"friend" : [ { "id" : "1234567802" } ]
}
{
"id" : "1234567802",
"type" : "person",
"name" : "Angelina",
"lastname" : "Jolie",
"age" : 43,
"city" : "Los Angeles"
}
The 'car' collection (3 documents)
{
"id" : "1234567803",
"type" : "car",
"model" : "Bugatti",
"color" : "blue",
"year" : 2015,
"number" : "US 1234",
"owner": [ { "id" : "1234567801" } ]
}
{
"id" : "1234567804",
"type" : "car",
"model" : "Mercedes",
"color" : "black",
"year" : 2014,
"number" : "US 4444",
"owner": [ { "id" : "1234567801" }, { "id" : "1234567802" } ]
}
{
"id" : "1234567805",
"type" : "car",
"model" : "Bentley",
"color" : "blue",
"year" : 2015,
"number" : "US 1234",
"owner": [ { "id" : "1234567801" }, { "id" : "1234567802" } ]
}
Using special methods, that are not detailed here, it is possible to "embed" documents, i. e., include them "by value", not by "reference".
# Correspondence rules
# Correspondence of relational and internal data models
- Table rows in relational tables are records of the internal model.
- Table names are record types. If a record has multiple types, then this record appears in multiple tables.
- Table column names are names of record fields. Values in particular columns are values of respective fields. For example, the value in the 'id' column is the record identifier.
- Records of the same type may have different field sets. The column set of a table that corresponds to this type will be a 'union' of these field sets, and if a record doesn't have a field, then the respective column will contain the NULL value.
- Values of fields that have the same names may, however, have different scalar types. It is possible to set up whether a single column of "variable" type or different columns will be created.
- Links between records are represented as "intermediate" tables. Additionaly, special columns with "multiple" foreign keys are created in "source" tables (see the above example).
# Correspondence of document and internal data models
- Document corresponds to the internal model record; document fields correspond to record fields. In particular, document identifier (
id
) corresponds to record identifier. - Record links are represented as document fields. By default, values of such fields are arrays of identifiers of documents that correspond to linked records.
- Collections consist of documents that correspond to records of the same type. The same document can be present in multiple collections.