clojuredatomicdatascript

datomic / datascript beginner - can we have multiple schemas


very basic question to get me started. Suppose I have a database of sales by country:

[{:sales/country "CN" :sales/amount 1000 :sales/account "XYZ"} ...]

I would like to also have a list of facts about each country something like:

[{:country/short-name "CN" :country/long-name "China" ...}]

And then do queries of the type "list all sales that happened in China (using the long-name)".

Is that one database? How do I make it clear there are two distinct schemas? Do I transact the first schema then the sales data, and later the country schema and data?

EDIT: sorry my question wasn't clear. Here is live example:

(d/transact! conn
             [{:country/code "BR" :country/name "Brazil"}
              {:country/code "CN" :country/name "China"}])

(d/transact! conn
             [{:sales/country "CN" :sales/amount 1000 :sales/account "XYZ"}
              {:sales/country "CN" :sales/amount 1000 :sales/account "AAA"}
              {:sales/country "BR" :sales/amount 1000 :sales/account "BBB"}}
              ])

I was able to run a query to join the tables and get the results I wanted. What I don't understand is what is best practice to define my schema. Is it just one schema or two of them, one for each table. Can I do this:

(def schema {:country/code {:db/valueType :db.type/string :db/unique :db.unique/identity}
             :country/name {:db/valueType :db.type/string}
             :sales/account {:db/valueType :db.type/string :db/unique :db.unique/identity}
             :sales/country-code {:db/valueType :db.type/string}
             :sales/amount {:db/valueType :db.type/integer}

             })

And is there a better way to define in the schema that country/code and sales/country-code are the same "key"?

Thanks,


Solution

  • You can only have 1 schema, but that should be enough. Use namespace in keywords to distinguish between different “domains” (:country/* for info about countries, :sales/* for info about sales).

    Datomic is more of a column store, so any entity can have any attribute, and you can even mix different “tables” on a single attribute (I don’t recommend it, but it’s possible).

    Your use of :country/code is what Datomic calls “an external id”. This is also a good practice, although, there’s no way to specify that :sales/country is a reference to :country/code.

    What I suggest you do instead is make :sales/country a Datomic reference:

    :sales/country-code {:db/valueType :db.type/ref}
    

    and then link to it in transaction using lookup ref:

    @(d/transact! conn [{:sales/country [:country/code "CN"] :sales/amount 1000 :sales/account "XYZ"})
    

    This will make sure country with this code exist during transaction time. You’ll also get benefits like easy retrieving country info from sales using entities/pull.