Fork me on GitHub
#datomic
<
2017-08-09
>
favila01:08:37

Tempids are clojure defrecords @devth @hmaurer

favila01:08:48

That is why they print like maps

favila01:08:47

(type (d/tempid :foo))

favila01:08:59

You can check for that type

eoliphant16:08:49

hi, i have a modeling question. We’re kicking off a new project and one of the first things is coming up with a schema for people, orgs, etc. This is traditionally done with something like Parties and Roles. It makes sense logically, but most of the practical guidance is based on shoehorning that into a relational model. just wondering about doing it in a more “Datomicy” manner. I was thinking for something like Person (Party) and Customer (Role), that I’d have a person entity (:person/fname, :person/lname, etc) that refs a set of roles where one might be Customer (:customer/shippingaddress, etc)

hmaurer16:08:25

@eoliphant I am completely new to Datomic but I am working on my first project and had to think about a similar modeling question so I can share with you my approach (which might be flawed, who knows…)

hmaurer16:08:23

Roughly speaking, persons in my system are represented as “identities”, and roles as “facets”. An identity in my system can have a number of facets (administrator, coordinator, and a few others in my case)

eoliphant16:08:55

sure 😉 I’ve been using it a bit now for small services, so we haven’t hit many major modeling issues. Now we’re starting to attack the core domain so the now the fun begins

hmaurer16:08:17

Initially I modelled it as a :identity/facets attribute with cardinality many, but ended up moving to an attrbute per facet, e.g. :identity/administrator-facet, each of which may be null (I found it a bit easier to work with in my project)

eoliphant16:08:25

so you have something like :person/facets as a ref?

hmaurer16:08:18

Although in my project those “facets” are not just roles for access control, they are more like “profiles”, used both for access control and to store profile-specific attributes

hmaurer16:08:35

if that makes any sense

eoliphant16:08:02

ours is even more fun. As you may have varying ‘facets’ that provide context for your relationship with other persons/organizations.

eoliphant16:08:04

yeah totally

eoliphant16:08:28

‘roles’ in this context aren’t necessary atuhorization roles (though they may guide allocating them, etc)

hmaurer16:08:47

Mmh that sounds a bit similar to mine. My users might have multiple facets, with various attributes

hmaurer16:08:59

e.g. a user may be both an “administrator” and a “coordinator”

eoliphant16:08:12

that’s what we have

eoliphant16:08:26

further for us it’s like ‘a user is a coordinator for “organization a”’

hmaurer16:08:33

yes exactly

hmaurer16:08:38

for me it’s coordinator of a “sector”…

hmaurer16:08:41

same thing

eoliphant16:08:02

now the nice thing with datomic is automatic bidirectional refs

hmaurer16:08:05

although in your case you could imagine being coordinators of multiple organisations

hmaurer16:08:14

so my model with an attribute per facet might not work for you

eoliphant16:08:56

yeah but that’s close to what I was thinking

hmaurer16:08:35

No worries. Please share if you have any striking insights on how to deal with this stuff 🙂

eoliphant16:08:00

yeah i’ll definitiely post or blog it 😉

eoliphant16:08:30

I keep having to ‘de-relationalize’ my thinking lol

hmaurer16:08:04

Yeah 😄 I feel it’s very natural to think in terms of graphs when working with Datomic

eoliphant16:08:07

yeah it’s far more natural in most cases, it’s just decades of ‘thinking in tables’ lol

eoliphant16:08:32

I did some stuff with RaimaDB like two decades ago that was much closer to the way datomic works

hmaurer16:08:47

I had never heard of RaimaDB

eoliphant16:08:56

not surprising lol

eoliphant16:08:03

it was a hierarchical db

eoliphant16:08:14

we were using it for embedded stuff

eoliphant16:08:27

i odn’t even know if it’s still around

hmaurer16:08:35

Apparently it still has a website

eoliphant16:08:49

just just checked lol cool

hmaurer16:08:09

As I said I am new to Datomic, and one of the things hurting my brain at the moment is the amount of discipline you need to model data properly

hmaurer16:08:16

Datomic is basically a triple-store

hmaurer16:08:28

It’s very flexible in the way your data is modelled

hmaurer16:08:53

Which is both great and a bit scary

eoliphant16:08:25

exactly, you can do pretty much whatever you want lol

hcarvalhoaves17:08:03

@eoliphant if you namespace your attributes, then you don't need to treat it as inheritance

hcarvalhoaves17:08:16

e.g. any entity w/ :customer/shipping-address works as a customer

eoliphant17:08:56

yeah I’ve thought about that as well

eoliphant17:08:33

but that’s a pretty simplistic example for us, i’m trying to balance the flexibility of just dumping attrs on an entity and keeping the model relatively robust. I guess in object terms, what I was thinking was more composition than inheritance?

eoliphant17:08:37

granted in various contexts

eoliphant17:08:00

programattically i only care about certain attributes at given times

eoliphant17:08:12

which would work better with your example

eoliphant17:08:50

i think the main issue is that ‘you’ as a ‘person (Party) may assume certain roles in relation to other Parties

hcarvalhoaves17:08:48

I think this is outside the scope of the db - the point of datomic is using the database to store data

eoliphant17:08:52

So that’s where I’ve been wondering if the breakout of the role specifc stuff onto another entity might be in order

eoliphant17:08:07

sure, but i need to capture those relationships in the data

eoliphant17:08:27

like ‘find all customers for x’ or something

hcarvalhoaves17:08:48

queries are straightforward. e.g. a query like [?p :person/id ?some-id] [?p :customer/shipping-address] will return an empty set

hcarvalhoaves17:08:27

but the entity for that :person/id may valid in another context (not shipping someting)

hcarvalhoaves17:08:25

but this is different than querying like [?p :person/role :person.role/customer] or something like that

eoliphant17:08:39

yeah and I’ve got some stuff along those lines. I think customer might have been a bad example lol, as it’s actually straightforward to model it’s just that in this domain you might be a ‘customer’ with varying attributes depending on certain relationships

eoliphant17:08:56

no it’s not

eoliphant17:08:38

what I was saying that you might have :person/roles pointing to a ref of type customer, with additional data on it

eoliphant17:08:53

but yeah if it’s just simple ident

eoliphant17:08:07

then plopping them on the person is cleaner

hcarvalhoaves17:08:17

can two entities point to the same customer ref?

eoliphant17:08:05

two persons probably not. but the person and the thing that you’re a customer of

eoliphant17:08:09

but i see where you’re going

eoliphant17:08:31

if this stuff is particular to the person (customer) why is it another entity

hcarvalhoaves17:08:49

also, can you have a customer without a person? does that make sense?

eoliphant17:08:58

and generally no

eoliphant18:08:19

but we have some situations where that might be the case (not customers lol).

eoliphant18:08:31

but I think i’ll use that heuristic

eoliphant18:08:43

in that if it truly makes no sense by itself

hcarvalhoaves18:08:47

I think you're trying to model tables on top of datomic w/ refs

eoliphant18:08:50

put it on the person

eoliphant18:08:55

yeah that’s more than possible lol

eoliphant18:08:06

it’s an ongoing struggle

hcarvalhoaves18:08:29

if all this data is about the same "thing", they share an entity

eoliphant18:08:31

that i tend to fall into ‘rectangles’

hcarvalhoaves18:08:33

so just use attributes

eoliphant18:08:39

and to your point

eoliphant18:08:48

the role relationships

eoliphant18:08:55

could themsleves simply be other attributes

hcarvalhoaves18:08:26

another way to think about it is: you store facts, and queries project these facts into tables

eoliphant18:08:46

yes good point. I’ve done some other small greenfield projects and didn’t have too much of an issue with modeling around facts

eoliphant18:08:57

in this case i’m working on our legacy domain

eoliphant18:08:20

so kind of have to ‘unsee’ aspects of the current approach to get this right i think

hmaurer19:08:53

@hcarvalhoaves are you sure it is reasonable to store everything that is about the same “thing” under one entity? It seems problematic, particularly if you have a one-to-many relationship, where the many things could be considered to be a part of the “thing”

hmaurer19:08:06

you can’t really model that with attributes on a single entity; refs seem to make sense

hmaurer19:08:14

with :db/isComponent true

hcarvalhoaves19:08:47

if you have a one-to-many relationship <- then you don't have one entity anymore

hmaurer19:08:51

well, under your definition, I could (if I understand it correctly). The “many” pieces might not have an existence of their own (aka the answer to the question “can you have one of these without X?” would be no, where X is your “main” entity)

hcarvalhoaves19:08:54

e.g. in his case person and customer are just facets of the same entity - 1:1

hmaurer19:08:24

right, but you could easily conceive a case where person has many “administrator” facets for different groups, or similar

hcarvalhoaves19:08:40

can you give a concrete case?

hmaurer19:08:09

not really, because the only case I have in mind could be solved without having multiple facets of the same kind

hcarvalhoaves19:08:03

well, going back to eoliphant's example

hcarvalhoaves19:08:41

it boils down to this: if I assert entity e1 has :customer/shipping-address, does it matter what customer is?

hcarvalhoaves19:08:58

e.g. I could have :shipping/address

hmaurer19:08:00

mmh ok I think I see what you mean

hcarvalhoaves19:08:16

the notion of customer doesn't exist at the data level - it's in your application

hcarvalhoaves19:08:34

the only thing at the data level is that e1 has this new fact about it

hcarvalhoaves19:08:01

now, maybe it makes sense to assert that, at some point, this entity is now a customer. there are a few possibilities

hcarvalhoaves19:08:32

usually, turning into a customer means there will be unique fact you want to assert, e.g. :customer/ssn

hcarvalhoaves19:08:52

and then you can infer it started being a customer at the time of this transaction

hcarvalhoaves19:08:40

(and if you retract those attributes, it stops working as a customer)

hcarvalhoaves19:08:52

otherwise, usually you'll have a synthetic attribute like :customer/id

hcarvalhoaves19:08:30

either way, you have a way to distinguish what works as a customer or not in a query

hcarvalhoaves19:08:05

I just don't know if the notion of "customer" matters much e.g. an entity can have many :customer/* attributes but without :customer/shipping-address, this "customer" doesn't exist for logistics

hcarvalhoaves19:08:09

to get more philosophical here: in real life, is common to see many different interpretations of "is a", depending on who is consuming the data

hmaurer19:08:49

@hcarvalhoaves thanks, that’s very insightful. Bouncing off a small detail in your explanation: would you then have multiple “ids” attached to an entity, one for each of its “facets”? e.g. :person/id, :cuztomer/id, etc

hcarvalhoaves19:08:15

IMO it's fine, it's just another unique attr

hmaurer19:08:38

you talked about a problem I encountered in my project: I have a facet which has no attributes, so I need some “witness attribute” to know an entity has this facet

hcarvalhoaves19:08:40

the reason you usually need those ids is because entitiy ids are internal to datomic - you don't want to expose those

csm21:08:36

Am I totally off-base with this approach, or it it reasonable?

csm21:08:28

or would doing the map/frequencies calls be more advisable in the client-side code (and, we connect via the client API in this case)