Fork me on GitHub
#datomic
<
2016-12-14
>
val_waeselynck00:12:33

Fancy stuff like JSON queries and indexing may be difficult too. Same thing for triggers.

tjtolton00:12:34

so, don't have 30 fields that are blank for 60 percent of the records?

val_waeselynck00:12:07

that won't be a problem with Datomic

val_waeselynck00:12:28

it might be in Postgres, in which case you will have one more argument for migrating 😉

tjtolton00:12:38

interesting. So, the events coming in are json documents. I take it what you're saying is to avoid storing the events as JSON fields, but rather store them as proper records

tjtolton00:12:06

like, dont have a table thats just an autoincrementing id and a json doc

val_waeselynck00:12:11

it depends. Some portions of those documents may be just "raw data" that you never query against

val_waeselynck00:12:29

in which case you would store them as strings or bytes in Datomic aniway

val_waeselynck00:12:11

Oh yes, also, you may have issues with ids that are unique at the table-level

val_waeselynck00:12:28

you should make them unique globally if possible

tjtolton00:12:15

interesting. Does datomic even have a concept of multiple tables?

tjtolton00:12:32

or any kind of data segregation

tjtolton00:12:37

other than schema

val_waeselynck00:12:39

no, everything is an entity. I find it easier to think of the Datomic model as a graph

val_waeselynck00:12:17

well, not even that. Everything is a Datom. Entities are a mental representation that is superimposed on Datoms

tjtolton00:12:06

lol. If I could, I'd get you to write a whole blog post on how datomic is like a graph. The business side of my company got hold of the concept of graph based data models, and they sell it as part of the product pitch

tjtolton00:12:07

If I could prepare a solid presentation on why datomic is a better fit for a graph model than relational, I'd be 80% the way there.

val_waeselynck00:12:10

Basically, datoms are edges, and entities and scalars are the vertices. Datalog is pattern matching in the graph. Really, visually, it's literally what it does.

tjtolton00:12:58

huh, interesting!

tjtolton00:12:07

hadnt thought of it like that, but youre right

tjtolton00:12:32

yessss, nice

val_waeselynck00:12:54

The fact that querying is not remote lets you program graph traversal from your application code, in your favorite programming language

val_waeselynck00:12:15

in that sense, the Entity objects are like cursors in the graph that is the DB.

val_waeselynck00:12:10

Finally, regarding business logic, don't forget to mention Datalog rules (noun, not verb) as a means of business abstraction.

val_waeselynck00:12:48

The last thing I would add is programmability. Generating Datalog is way easier than generating SQL, trust me.

tjtolton00:12:06

its going to be a tough sell nomatter how I do it. Our senior data architects are SQL engineers through and through.

val_waeselynck00:12:33

Tell them they can use Postgres as Datomic's storage service 😉

tjtolton00:12:32

Hahahaha, I'm sure they'll tell me "we have bigger priorities than adding new things to our tech stack"

tjtolton00:12:55

but hey, thats software

val_waeselynck00:12:20

Tell them that of all their issues, having to learn a new tool is the only one that is guaranteed not to get worse

tjtolton00:12:04

I might be able to spin that, yeah. Introducing it as a tool is the way to go.

tjtolton00:12:25

I shouldn't say that I want to change the system, I just want to add a new tool.

tjtolton00:12:39

I like that.

val_waeselynck00:12:06

it depends how much you rely on stuff like ORMs I'd say.

tjtolton00:12:09

So, you're probably going to double take when I say this, but that's not a problem, because our code base is all written in clojure so there are no objects.

tjtolton00:12:56

Yes, that's right, I am in the strange position of fighting an uphill battle trying to sell datomic to a clojure shop.

val_waeselynck00:12:18

Personally, Datomic was maybe the main reason I moved our stack to Clojure.

val_waeselynck00:12:52

Clojure is pretty cool on its own, but Datomic gives it a lot of leverage.

tjtolton00:12:33

Its a very strange thing. The company has used clojure since 2010

tjtolton00:12:49

in production mind you

tjtolton00:12:34

so a lot of the system was architected before some of clojure's interesting ecosystem had evolved around it

val_waeselynck00:12:50

Well, one thing that is sure is that for them to add Datomic to the stack, the case for Datomic needs to be compelling, otherwise the additional complexity may just not be worth it. You should ask yourself this question honestly.

val_waeselynck00:12:45

Maybe you can start with Postgresql, and watch out for situations where Datomic makes things much easier (N+1 problem, sparse data, graph-type queries, ...)

val_waeselynck00:12:25

then importing the data into Datomic and demoing how it deals better with these issues should not be too hard, maybe a couple of days

tjtolton00:12:39

I'll definitely be examining this question for a while before I try to make the sell

tjtolton00:12:57

I'll be catching up on your blog 🙂

val_waeselynck00:12:26

@tjtolton thanks 🙂 be critical!

val_waeselynck00:12:43

Need to go to sleep now, but don't hesitate to let me know how it goes.

tjtolton00:12:04

Thanks for the help @val_waeselynck! Goodnight.

wei01:12:54

working on a schema here, is it beneficial to have each entity type have its own uuid property? e.g. :user/uuid and :team/uuid vs plain :uuid? and what would be the benefit?

wei01:12:15

also for one-one relationships what’s the tradeoff in pulling everything into one entity vs splitting it into a (component) entity? e.g. a team has a set of credentials. so I might have the following properties: :team/id, :team/members, :team.creds/email, :team.creds/token. should those go into one entity or two separate ones?

bhagany03:12:23

@wei I’m no expert, but fwiw, I would use the same uuid attribute for entities that I expected to query across. So, using your example, if I thought I was going to do something like :where [?user-or-team :uuid ?uuid], I’d use the general one, but if it’s always like :where [?user :user/uuid ?uuid], then the more specific ones are fine.

bhagany03:12:57

For my own use case, I use a general attribute, with a semantically broad namespace

bhagany03:12:15

@wei for your second question, I would put all of those attributes in the same entity

bhagany03:12:50

I think components make the most sense for :cardinality/many references

Matt Butler09:12:24

When you pass a java.util.date into a query is it cast to a long so it can be compared against a :db/instant like so (> ?dbintant ?javautildate)?

wei17:12:17

@mbutler I believe they are compatible (= (type (java.util.Date.)) (type #inst “2016”)) => true

wei17:12:33

I find myself repeating (map (partial d/entity db)) a lot in my helper functions, e.g.

(defn all [db]
  (->> (d/q '[:find [?e ...]
              :where [?e :team/uuid]]
            db)
       (map (partial d/entity db))))
is there a better abstraction that avoids this duplication?

Matt Butler17:12:55

@wei Right, (> java.util.Date java.util.Date) is not valid clojure code as > needs integers. If you store a util date as a :db/instant it becomes a long so you can use < on it. However it also seems if you pass a util date into a query it is coerced into a long. Wanted to check I wasn’t incorrectly making a huge presumption.

Matt Butler17:12:58

(> :db/instant java.util.Date) inside a query works which is super interesting and how I’ve been doing it 😄

rnandan27319:12:45

Hi, Followed instructions using heroku datomic build as specified here https://elements.heroku.com/buildpacks/opengrail/heroku-buildpack-datomic but i keep getting error stating

rnandan27319:12:47

Device "eth1" does not exist. 2016-12-14T18:56:43.386579+00:00 app[datomic.1]: sed: can't read /app/scripts/transactor.properties: No such file or directory 2016-12-14T18:56:43.398163+00:00 app[datomic.1]: Picked up JAVA_TOOL_OPTIONS: -Djava.rmi.server.useCodebaseOnly=true 2016-12-14T18:56:43.389335+00:00 app[datomic.1]: Launching with Java options -server -Xms256m -Xmx2g -Ddatomic.printConnectionInfo=false 2016-12-14T18:56:47.326896+00:00 app[datomic.1]: Critical failure, cannot continue: Error starting transactor 2016-12-14T18:56:47.327568+00:00 app[datomic.1]: java.lang.Exception: 'protocol' property not set 2016-12-14T18:56:47.327669+00:00 app[datomic.1]: at datomic.transactor$ensure_args.invokeSt

rnandan27319:12:25

Any ideas? i have heroku postgress up and running

wei19:12:17

echoing in case anyone has a good answer:

djjolicoeur19:12:54

could use the pull api inside the query, but that assumes you know the shape of the data you want up front and don’t want to leverage the cursor-like nature of entities

robert-stuttaford19:12:07

@wei, basically, no. 🙂

robert-stuttaford19:12:54

@wei well, that’s not strictly true. i wrote some transducer backed helpers:

robert-stuttaford19:12:03

(defn to-entity-for-db [db]
  (partial d/entity db))

(defn ids-as-entities
  ;; transducer
  ([db] (map (to-entity-for-db db)))
  ;; actually do the work
  ([db ids] (sequence (ids-as-entities db) ids)))

(defn datoms-as-entities
  ;; transducer
  ([db] (comp (map :e) (ids-as-entities db)))
  ;; actually do the work
  ([db datoms] (sequence (datoms-as-entities db) datoms)))

robert-stuttaford19:12:42

so your example would change to (ids-as-entities db (d/q '[...] db))

robert-stuttaford19:12:02

you can see i have one for use with d/datoms too

wei19:12:56

@robert-stuttaford i’m finding your helpers useful, do you have a lib or gist of any more useful ones?

robert-stuttaford19:12:03

i’m toying with the idea of releasing a library with this stuff 🙂

wei19:12:22

thanks for sharing! I’ve also tried building helper layers in various forms, but am now of the opinion that small convenience functions work better than a substantial wrapper library. eventually I run into cases where those wrappers fail and I need to drop down into base api

robert-stuttaford19:12:48

the trick is not to wrap, i think, but to make useful shortcuts to compose the base api with

robert-stuttaford19:12:21

if you try to hide the base api away, you’re losing (i have this t-shirt 🙈 )