This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-09-13
Channels
- # announcements (15)
- # babashka (48)
- # beginners (5)
- # biff (4)
- # calva (3)
- # cider (10)
- # clerk (16)
- # clj-kondo (6)
- # cljdoc (20)
- # cljs-dev (13)
- # clojure (117)
- # clojure-argentina (1)
- # clojure-brasil (5)
- # clojure-europe (40)
- # clojure-nl (1)
- # clojure-norway (111)
- # clojure-uk (5)
- # clojurescript (16)
- # cursive (20)
- # datascript (2)
- # datomic (106)
- # etaoin (2)
- # events (3)
- # funcool (1)
- # graphql (1)
- # helix (8)
- # hyperfiddle (36)
- # leiningen (12)
- # matrix (1)
- # nrepl (1)
- # off-topic (61)
- # other-languages (10)
- # polylith (22)
- # practicalli (1)
- # reagent (28)
- # reitit (11)
- # remote-jobs (3)
- # ring (12)
- # shadow-cljs (109)
- # slack-help (6)
- # solo-full-stack (23)
- # squint (7)
- # xtdb (11)
AWS recommends a separate account when doing Amplify work. Has anyone found this necessary for Datomic/Ion-based systems? Seen any Amplify provisioning collisions?
Pure curiosity on my part, do you have a link to the docs where AWS makes that recommendation?
I knew someone would ask. I went looking for it and couldn’t put my hands on it. I’ll double down.
I haven’t found it yet. If I didn’t see it, the hallucination was strong enough for me to create a separate account. If I trip over it again (while I’m tripping over myself), I’ll pipe up.
I, too, don’t remember seeing such documentation. We have a few Datomic Cloud deployments in different AWS accounts (managed with AWS Control Tower), each with its own Amplify deployment for our frontend, in the same account as its Cloud Ion backend. No issues.
With that said, we didn’t invest a lot in Amplify-typical tooling. We used it mostly for its ease of use, so we didn’t feel the need to read much of their docs…. so I must see I can see the possibility that for people who go all-in on the entire Amplify frontend & backend stuff, it might be written some place that it’s recommended to do all that in its own AWS account. Since you’re most probably going the “Amplify frontend only” + “Datomic Cloud Ion backend” route, I don’t feel the advice would be very valuable.
Yes, Datomic/Ion back end. As I see it, AppSync is the line. Everything from there forward being more the Amplify world. That’s my current thinking anyway. Thanks.
I’m trying to find an entity o that is referenced by other entities of kind a, with at least one of each kind of a supplied. This query is crushing my machine, on quite paltry amounts of data. what am I doing wrong?
(d/q '[:find [?o ...]
:in $ ?a ?b
:where
[?ia :a/kind ?a]
[?ib :a/kind ?b]
[?ia :a/entity ?o]
[?ib :a/entity ?o]]
(d/db conn!)
:a.kind/a
:a.kind/b)
Try with :query-stats https://docs.datomic.com/pro/api/query-stats.html
e.g. maybe ?ia -> :a/entity -> ?o -> :a/_entity -> ?ib
realizes fewer intermediate rows
(d/q '[:find ?o
:in $ ?a ?b
:where
[?ia :a/kind ?a]
[?ib :a/kind ?b]
[?ia :a/ref ?o]
[?ib :a/ref ?o]]
'[[a :a/kind :a]
[b :a/kind :b]
[c :a/kind :b]
[a :a/ref f]
[b :a/ref f]
[c :a/ref g]]
:a
:b)
..gives me the right answer, for example, although yes, its just dumb datanice thing about datalog is clause order doesn’t affect its correctness, just its performance
If :a/kind is high-cardinality, I suspect this will be faster
[?ia :a/kind ?a]
[?ia :a/entity ?o]
[?ib :a/entity ?o]
[?ib :a/kind ?b]
so thousands is high cardinality, because after the first two clauses you will have ?ia * ?ib rows
sounds like my mental model of the query isn’t quite right - I was thinking of each clause producing a set of values, and then the answer is the intersection of those clauses… ?
this is the “join along” rule of thumb in https://docs.datomic.com/pro/best-practices.html#join-along
yup, sadly no good! I tried different combinations here, including your suggestions, thank you, and they are all timing out on thousands of rows. Doing the set intersection by hand, however, is milliseconds.
[?ia :a/kind ?a]
[?ia :a/entity ?o]
[?ib :a/entity ?o]
[?ib :a/kind ?b]
I tried this ordering, and same thing, sadlyactually, no - your ordering and join along is the right solution
{:query [:find
[?o ...]
:in
$
?a
?b
:where
[?ia :incident/kind ?a]
[?ia :incident/organizations ?o]
[?ib :incident/organizations ?o]
[?ib :incident/kind ?b]],
:phases [{:sched (([(ground $__in__3) ?b]
[(ground $__in__2) ?a]
[?ia :incident/kind ?a]
[?ia :incident/organizations ?o]
[?ib :incident/organizations ?o]
[?ib :incident/kind ?b])),
:clauses [{:clause [(ground $__in__3) ?b],
:rows-in 0,
:rows-out 1,
:binds-in (),
:binds-out [?b],
:expansion 1}
{:clause [(ground $__in__2) ?a], :rows-in 1, :rows-out 1, :binds-in [?b], :binds-out [?a ?b]}
{:clause [?ia :incident/kind ?a],
:rows-in 1,
:rows-out 49947,
:binds-in [?a ?b],
:binds-out [?b ?ia],
:expansion 49946}
{:clause [?ia :incident/organizations ?o],
:rows-in 49947,
:rows-out 3560,
:binds-in [?b ?ia],
:binds-out [?o ?b]}
{:clause [?ib :incident/organizations ?o],
:rows-in 3560,
:rows-out 49411,
:binds-in [?o ?b],
:binds-out [?o ?ib ?b],
:expansion 45851}
{:clause [?ib :incident/kind ?b],
:rows-in 49411,
:rows-out 16,
:binds-in [?o ?ib ?b],
:binds-out [?o]}]}]}
{:clause [?ib :incident/organizations ?o],
:rows-in 3560,
:rows-out 49411,
:binds-in [?o ?b],
:binds-out [?o ?ib ?b],
:expansion 45851}
and then, ordering the inputs from lowest to highest cardinality makes it more efficient
(defn other-edges-sharing-attr+v [db ^long e attr]
(eduction
(mapcat #(d/datoms db :vaet (:v %) (:a %)))
(remove #(== e ^long (:e %)))
(d/datoms db :aevt attr e)))
[?ia :incident/kind ?a]
[(other-edges-sharing-attr+v $ ?ia :incident/organizations) [[?ib _ ?o]]]
[?ib :incident/kind ?b]]
I’m electing to create a domain attribute to track “created-at” and “updated-at”. Ideally, I would like these values to default to :db/txInstant
but I would even be happy with opt-in setting them to :db/txInstant
. Is there a built-in way to access :db/txInstant
or is it possible to access that value in a transaction function? My fallback would be to set both :db/txInstant
and my domain values from the same wall clock time (in a transaction function to avoid inconsistencies with multiple clients).
If a join is acceptable to you, you could make created-at and updated-at a reference to the tx instead
Sorry… I am just now appreciating that your suggestion was to create a reference to the tx -not just a time value.
In cloud, I assume I can use the “usual” string representation of the tempid for the tx like this…
[{:my/created-by "datomic.tx"
...}]
I'm trying to get the latest transaction that modified an entity, is this the best approach? 🧵
(d/q '[:find (max ?tx) .
:in $ ?e
:where [?e _ _ ?tx _]]
(d/history db)
17592212457845)

It’s really the only approach. It may be a little less memory-intensive to reduce over d/datoms :eavt, but it’s doing the same thing fundamentally
I think this works too, but feels like a bad idea
(d/t->tx (dec (d/tx->t 17592212457845)))
Thank you!!it tells you some T > the T of the TX which minted the entity id and <= the T of the following TX
If that is so, it’s because you haven’t asserted or retracted anything on the entity since the transaction that created it
There’s a single T counter in the db, and transactions and entities are both minted from the same T, so the T of entity ids do interleave like TX1 entity-id-minted-in-TX1 TX2 entity-id-minted-in-TX2 etc
that can happen via aborted txs; but even without that the T may belong to another entity that is not a TX
oooh ok, so for example if I have a transaction that adds 2 new entities, the counter should increase at least by 3?
> d/tx->t
just strips the partition bits, giving you the T
Quoting your https://observablehq.com/@favila/datomic-internals article! (thanks again)