Multi-modelity

General information

NitrosBase is a multi-model database which supports the following models:

  • relational,
  • graph,
  • document.

In NitrosBase, 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 NitrosBase 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.