Fork me on GitHub
#datomic
<
2024-03-10
>
itaied12:03:51

hey all how can I group up queries that include "many" cardinality? for example:

(d/q [:find ?user ?group
      :where
      [?u :user/name ?user]
      [?u :user/group ?g]
      [?g :group/name ?group]])
I'm receiving the results as repeating user names for each group, and I want the result to be group in a vector for the group:
[{:user "u1"
  :groups ["g1" "g2"]}
 {:user "u2"
  :group ["g1" "g4"]}]
should I just write ad-hoc code for that or datomic has some aggregate / grouping functionality?

favila13:03:35

Datomic can do this, look for “aggregate” in the docs. Eg :find ?user (vec ?groups)

itaied14:03:36

prefect it worked, thanks While I'm at it, I'm trying to modify the values of the groups. I'm receiving as an input the current groups of the user. I want to remove all the group he currently part of and add the new ones. I have tried retract and add in the same transaction but it failed:

(d/transact conn [{:user u
                   :groups [{:name g-name} ...]}
                  [:db/retract [:user u] :groups]])
Two datoms in the same transaction conflict

jjttjj17:03:04

Woah I never knew vec could be used like this. Is there a way that you can call pull in the query on the things you're calling the aggregate function on? like

:find ?user (vec (pull ?groups [*])
That gives me
IllegalArgumentException Argument (pull ?groups [*]) in :find is not a variable
Edit: hmm I think maybe a subquery doing the pull would work, trying that out now

favila17:03:20

You can write your own aggregate fn (read the docs). If you are on on-prem, it’s usually pointless to try and stuff everything into a query

👍 1
favila17:03:08

Just use group-by and/or pull-many

favila17:03:05

Re: retract and add, you can’t retract and add the same value in the same tx; you need to retract the specific ones which will be gone. If you want to do this in a race-proof way, write a transaction fn which accepts the full set of values you want and returns the adds/retracts needed to make that the final value

👍 1
itaied18:03:42

Understood. thank you

cch114:03:45

Since vec is not documented in the https://docs.datomic.com/cloud/query/query-data-reference.html#aggregates, I wonder if there are other aggregate functions I've been missing. I also wonder if the (also undocumented AFAICT) function signature of custom aggregates just happens to match that of the built-in "ambient" fn vec...

favila14:03:10

vec in my example is clojure.core/vec

favila14:03:46

function signature of custom aggregates is documented

cch114:03:16

(but pro probably is good docs too for DC)

favila14:03:17

IDK cloud, but I doubt its significantly different

favila14:03:31

actually I wonder if I could just use identity instead of vec

jjttjj14:03:51

Works on cloud too. I had a similar line of thought that vec must be some "special" built in before realizing it's clojure.core/vec and having a mini "aha moment" about how the aggregates work

cch114:03:55

Seems like it, based on the docs you provided

favila14:03:10

I’d worry about any reference-holding it might do

favila14:03:15

IDK its internals

favila14:03:37

on cloud though that would be fine--it’d just get serialized

favila14:03:44

(well unless it was an ion in-process)

favila14:03:24

re aggregates, they’re more like collection transformers. There’s nothing fancy going on with windowed aggregates like some other dbs offer, because all results are fully realized before the grouping happens

favila14:03:34

that’s why the fn signature is so simple