Datomic 的 schema 比 SQL 資料庫靈活得多,這邊從三個不同的面向來探討靈活性:
NULL
值NULL
值如果一張表 people
有三個資料實體,資料實體是三個人的基本資料,只有一個人有職業。
{:name "John"
:age 55
:sex "Male"
:job "Engineer"}
{:name "Mary"
:age 45
:sex "Female"}
{:name "Jack"
:age 20
:sex "Male"}
在 SQL 資料庫裡,由於每張表的欄位是固定的,如果要記錄這樣子的資料,只有兩種選項:
people
這張表定義四個欄位,並且讓 Mary, Jack 兩個資料實體的 job
欄位都填入 NULL
值。people
這張表只定義三個欄位 name
, age
, sex
。並且另外定義一張 job
表,並且在 job
表產生一個欄位指向 people
表,日後存取時需要做 join
。在 Datomic 裡,綱要的最小單位不是表,而是欄位。這種欄位綱要 (column schema) 又稱之為屬性。以這個例子的話,Datomic 可以定義如下的欄位綱要。
(def schema
[{:db/ident :people/name
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one}
{:db/ident :people/age
:db/valueType :db.type/long
:db/cardinality :db.cardinality/one}
{:db/ident :people/sex
:db/valueType :db.type/long
:db/cardinality :db.cardinality/one}
{:db/ident :people/job
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one}])
資料實體在 Datomic 裡,可以想象成像是用程式語言裡的字典結構來儲存,如果缺了特定的欄位,就是讓那個屬性不存在,不需要使用 NULL
值。
如果我們定義了一個 Datomic 屬性 (即欄位綱要),它代表了一個資料實體開始的時間,它可以定義成:
{:db/ident :time/start
:db/valueType :db.type/instant
:db/cardinality :db.cardinality/one}
我們可以把這個欄位綱要,套用到 people
表以表示人的生日;也可以套用到 car
表以表示汽車的購入時間。一旦這麼做之後,如果日後我們想找出,比某一天 date
更早的所有資料實體,我們就可以使用下列 Datalog 查詢找出來。無論是人或是車都可以一次找出。
[:find ?e
:in $ ?date
:where [?e :time/start ?t]
[(< ?t ?date)]
在 SQL 資料庫,當我們需要建模 (model) 多對多的關係 (many to many relationships) 時,我們往往必須設計一張橋接表 (bridge table) 。
在 Datomic 資料庫,我們不需要做這件事,因為我們可以把 :db/cardinality
設定成 :db.cardinality/many
,意思是:這個欄位綱要它可以『一對多』。如果有使用過圖學資料庫,比方說 neo4j ,的讀者,可以想象成 Datomic 允許你定義『邊』(edge)。