In Part 3 we claimed »Inheritance and the flexibility of the graphical vertex & edge approach open sudden opportunities.« Let's prove it right away.
The power of RID
OrientDB
is a »multi model database«, capable to act as a (SQL)RDMS-, a KeyStore- and a Graph-Database. The KeyStore-Design requires the presence of an universal Key, that's RID
.
Each record has a RID
, each Object is fully identified through its RID
. Simple, but powerfull.
> Person.last.rid => "34:0"
> "#34:0".expand.to_human
=> "<Person[34:0] (...) >"
Data-items loaded from the database carry their class-id. ActiveOrient
autoloads the object and assigns the corresponding ruby-class. Thus any method defined in the model is accessible, any attribute is present as well as any join and any connected edge is waiting to be discovered.
Time Grid
Think of a mesh of date-items, supporting one central goal: Provide an even access-time to any Date of a given time-period, to any item connected to the grid.
This Graph is realized
Jahr -- [MONTH_OF] -- Monat --[DAY_OF]-- Tag --[TIME_OF]-- Stunde
The nodes are crosslinked via GRID_OF-edges and any point of the grid is easily accessed.
To use the time-grid, install the OrientDB-Time-Graph-Gem. It creates the grid and defines a method to_tg
for String
and Date/Time
,
> Date.today.to_tg.datum
=> Fri, 02 Aug 2019
# and
"4.6.2015".to_tg
=> #<TG::Tag:0x00000000043c8c60 (...)
Store Items
By simply assigning
a database-record to the Tag
-Object, the universal store facility is created.
Lets go back to our family of Part 3 and assign Seema's
birthday. We use a specialized edge-class HAS_BIRTHDAY
> E.create_class :has_birthday
> sema = Child.where( name: 'Seema').first
> "20.6.2010".to_tg.assign vertex: sema, via: HAS_BIRTHDAY
Query
Let's consider two use-cases
- we just want to know Seemas birthday
- we are interested in all birthdays in June 2010
Seemas Birthday
We can simply get the Child-Record and follow the link to the time-grid.
> sema = Child.where( name: 'Seema').first.to_human
"<Child[147:0]: in: {IS_CHILD=>1, HAS_BIRTHDAY=>1}, name : Seema>"
> seema.nodes(:in, via: /birth/).datum # firing a query
#or
> seema.in_has_birthday.out # performs action in ruby
=> [Sun, 20 Jun 2010]
This is similar to an RDMS(SQL)-approach.
Any Birthday in a given range
Suppose, you got a huge database, full of birthdays and want to mine the data. In the RDMS-World you would query the hole database-table. The more data, to longer it takes. Even if you are just interested in People with Birthdays in the same month then Seema, there is no way to avoid accessing all birthday-records in store.
The »Time-Graph« offers constant access time regardless of the size.
We just jump to one boundary of our range of interest and traverse the next 30 day-records.
> start = "1.6.2010".to_tg
> start.vector( 30 ){ :out_has_birthday }
# INFO->select out_has_birthday from ( traverse outE('tg_grid_of').in from #55:5042 while $depth < 30 ) where $depth >= 0
=> ["#52:5043"]
> start.vector( 30 ){ :out_has_birthday }.expand.nodes(via: /birth/).to_human
=> [["<TgChild[147:0]: in: {TG_IS_CHILD=>1, TG_HAS_BIRTHDAY=>1}, name : Seema>"]]
The method »vector« encapsulates the traverse query. We follow 30 time-grid-links (30 days) and are looking for an property »out_has_birthday«. The query returns an array of RID
's (of Time-Grid-Elements). We expand them manually and follow the link HAS_BIRTHDAY
.
If we are interested in the count of birthday's in a specific range:
> start.vector( 30, function: :count ){ :out_has_birthday }
=> 1
Conclusion
Database Design matters, even if a flexible multi-model-database is used. This simple pattern opens a door to »sustainable programming«. In contrast to classical RDMS(SQK)-Databases, using a Time-Grid, time-dependent data are stored in an unified environment. Queries are time-invariant. That means: if a database matures, grows and evolves, on can expect constant access times to its heart: the Time-Grid. The possibility of an assignment of any (seriable) ruby object to the time-grid is self evident.
Top comments (0)