Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the more idiomatic option in Datomic land for this schema?

I have a question regarding what's a more idiomatic schema for Datomic.

Let's say we have the entities User, Post and Topic.

Post can belong to Topic, User and other Post (replies). Now, should I,

a) Create a :posts attribute, that is just a list of Posts, and inject that into every entity that requires reference to a number of Posts?

or

b) Establish more explicit relationships, such that a Post has a :post/author attribute that is a ref to a User, and perhaps a :post/belongs-to attribute that can refer to either a Topic or another Post?

Observations: If I do b, I seem to get more semantic relationships. I can for example do (:post/_author user-entity), which is more descriptive of the nature of their relationshop than is (:posts user-entity) (since, what does it mean that a User has :posts? Are those the Users favorited Posts, authored Posts, or what?)

Another side effect of b is that I can create a new Post without mutating any other entity. If I do a, I need to create the Post and also insert it into the :posts attribute of User, requiring two operations instead of one.

However, I have a feeling that a might be the more idiomatic way of doing it. It seems, for example, that it would be easier to see how the list of the attribute :posts have changed over time, should I want to do it, if User references :posts rather than having Post reference User through the :post/author attribute.

What would be preferable, and why?

like image 329
Henrik Avatar asked Nov 19 '13 10:11

Henrik


1 Answers

Your option (b) is essentially the idiomatic and only way to go in datomic.

All datomic schema is codified only as what values an attribute can take in the structure of an entity-attribute-value datom (EAV).

See http://docs.datomic.com/schema.html - a key proposition taken from the docs is:

Each Datomic database has a schema that describes the set of attributes that can be associated with entities. A schema only defines the characteristics of the attributes themselves. It does not define which attributes can be associated with which entities.

Entities themselves are highly abstract (and internally are just numbers), all the interesting properties of entities are codified as attribute-value assertions. Entities are not typed! You create the semantics of an entity by what attributes you assert for it such as :user/firstname, :post/title, :post/content, :topic/description etc. This is why you really really want to namespace the attributes.

A special case of this is the attribute type :db.type/ref where the value of "V" in EAV is itself another entity. This is what creates semantic associations between entities. You give each attribute a "name" (as a :db/ident) to capture what the E<->E connection actually means. So you could have an attribute of :db.type/ref with the :db/ident ":post/author".

Note that all :db.type/ref attributes are inherently bidirectional so if Eu is an entity representing a user and Ep is an entity representing a post then the following are equivalent both in datom creation and query:

[Ep :post/author  Eu]
[Eu :post/_author Ep]

All entity relationships being just more attribute assertions is really flexible. If you later want to add the concept of favorite posts it is just another attribute of :db.type/ref. Create it with a :db/ident such as ":user/favorites" and assert connections between preexisting users and posts (which have different user entities as authors).

[aUser :user/favorites somePost]

There is no notion of collection valued attributes so what you suggest in (a) is not properly expressible in datomic. You would use query to aggregate the posts. Post deletion would be modeled by a retraction of the entity itself. Such a retracted post will remain visible in the database history.

This does create a challenge of how to specify an order for lists of entities. You either need to use a "natural" ordering such as the date of a post (captured either in the datomic transaction or as an explicit attribute of the post) or use explicit attribute-value based ordering such as via a :post/up-votes numeric attribute.

If you need semantic grouping of entities, where "sub-entities" are only meaningful and only exist as part of something bigger - e.g. the line item entities in an order - then see datomic components.

like image 78
Alex Stoddard Avatar answered Sep 28 '22 04:09

Alex Stoddard