datomic

Ask questions on the official Q&A site at https://ask.datomic.com!
2020-12-07T19:12:54.076800Z

when writing a ref attribute, how can we indicate the type? or is that deliberately omitted because datomic (and perhaps clojure) doesn't make use of types, only attributes? in some codebases, i see idents out there called "schema namespaces", and the attr would indicate it is associated with that schema (as would the refed entity, perhaps). or is it best to have the attr namespaced to match the refed entity?

2020-12-07T19:14:52.077Z

i wonder if that last option - matching the attr namespace to the namespace of the ref'ed entity - is always suitable. for example, you might have a :person/child attr ref to another :person entity. then the namespaces wouldn't match.

favila 2020-12-07T19:24:42.077200Z

entities are untyped (they’re just an ID to join facts together), so refs are also untyped

favila 2020-12-07T19:25:24.077400Z

e.g. what makes an entity a “person”?

favila 2020-12-07T19:27:13.077600Z

You could layer a type system on top. a common approach is to add additional attributes to the ref attribute itself that indicates (human or machine-readably) the range (such as type) may have

favila 2020-12-07T19:27:44.077800Z

a more recent feature is to use a pair of entity specs with db/ensure: https://docs.datomic.com/on-prem/schema.html#entity-specs

favila 2020-12-07T19:28:35.078Z

spec the referent, spec the referred, and add an entity predicate to the referent that asserts that the referred conforms; then add a :db/ensure when you transact changes to the referrer

Raymond Ko 2020-12-07T21:56:32.084Z

Is there a canonical direction in modeling parent-child relationships in datomic schemas? For example, consider a schema which represents books and their respective chapters. I see two ways. 1. have a :book/id , :chapter/id and :book/chapter where book -> chapter. In order to delete the chapter you have retract the chapter entity and one of the db.cardinality/many attributes in the book entity (just realized refs solve this problem, ignore this). 2. have a relationship where chapter -> book. like :chapter/book. This is a db.cardinality/oneand has the benefit of only needing to retract the entity to delete. My main issue of this is that it seems reversed and for more complicated cases, it is not always clear it is like :child/parent especially when there is domain specific terminology, Is there a standard convention like :chapter/book-parentor :chapter/parent-bookto denote attributes of this type?

benoit 2020-12-07T22:05:20.084200Z

One difference is that you can use :db/isComponent on :book/chapter but probably not on :chapter/book.

2👍
2020-12-07T22:06:32.084500Z

Was just about to say, but don’t you get a many-to-many relation from that

benoit 2020-12-07T22:08:54.084700Z

I'm not sure what you mean. https://docs.datomic.com/cloud/schema/schema-reference.html#db-iscomponent

2020-12-07T22:10:56.084900Z

I meant to say, if you make :book/chapter a ref-many component to a chapter, then pulling`:book/_chapter` on a capter entity also gives a set of books I think. Anyhow — Not particularly important for this discussion I’m confusing myself, ignore

benoit 2020-12-07T22:13:38.085600Z

I think you might be right though. The entity API might return a set of "one" book.

Raymond Ko 2020-12-07T22:14:43.085800Z

Thanks, I did not now about :db/isComponentand considering my own project nests further with other types and datascript supports this, it seems like there is only one way to go if I want easy deletions.

favila 2020-12-07T23:37:09.086200Z

@me1740 @lennart.buit isComponent also makes the “reverse” direction cardinality-one

1👍
favila 2020-12-07T23:37:23.086400Z

(even if there are multiple referents!)

joshkh 2020-12-07T23:40:55.086600Z

i agree that isComponent is the best solution here. if in the future you find that components might not fit your data model, you could consider writing transaction functions that handle data cleanup from a business logic perspective.. "when this book is removed from the library, retract chapters and user highlights about those chapters and any reservations for the book". i use a combination of tx fns and a "retraction api" that cleans up the messy parts of the graph, like related unique tuple constraints that no longer make sense when parts of their value are retracted (such as book+chapter+critic+rating -> nil+nil+critic+rating)

joshkh 2020-12-07T23:45:12.086800Z

i've often been tempted to add "reverse component references" between entities just for the sake of data cleanup, but after playing with the idea it felt wrong. components are great.. just saying that they might only get you so far before a tx fn becomes a better option 🙂

2020-12-07T23:53:45.087Z

Ah yeah @favila, I started doubting indeed ^^, testing it in the repl confirms you are right. Thanks!