This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-07-11
Channels
- # announcements (6)
- # babashka (35)
- # beginners (6)
- # biff (2)
- # calva (1)
- # cider (16)
- # clj-kondo (14)
- # clojure (176)
- # clojure-austin (13)
- # clojure-europe (7)
- # clojure-norway (6)
- # clojure-uk (12)
- # clojurescript (4)
- # cursive (11)
- # data-science (3)
- # datalog (10)
- # datomic (45)
- # events (1)
- # fulcro (2)
- # hyperfiddle (29)
- # leiningen (14)
- # lsp (2)
- # meander (2)
- # off-topic (24)
- # polylith (5)
- # re-frame (2)
- # shadow-cljs (21)
- # specter (14)
- # tools-deps (16)
- # xtdb (5)
Hi, I'm building an app where users can vote on statements, and votes are stored as datoms that relate to statements via a :vote/target attribute. I'm trying to write a query that will get all the statements and their votes count. Not sure if it should be all in one query. Anyway, this is where I've got so far:
(defn get-statements-data []
(d/q '[:find (pull ?e [:statement/content :statement/author]) ?d ?v
:where
[?e :statement/content _ ?tx]
[?tx :db/txInstant ?d]
[(missing? $ ?e :vote/_target) ?v]
] @db/conn)
)
I feel like I'm navigating without a map, any hint will be appreciatedIf I understood the question correctly, perhaps this gist can help? https://gist.github.com/vvvvalvalval/5547d8b46414b955c88f
Thank you! that's perfect. I also saw this answer on stackoverflow on the same topic https://stackoverflow.com/questions/47417009/datomic-aggregations-counting-related-entities-without-losing-results-with-zero?noredirect=1&lq=1
Another question, My db has votes that have the attributes: :vote/user :vote/target :vote/value and :vote/event(an attribute that represents a contest in which the vote is cast) I want each user to be able to vote once per target+event, so I created a composite tuple adding a uniqueness constraint:
{:db/ident :vote/target+user+event
:db/valueType :db.type/tuple
:db/tupleAttrs [:vote/target :vote/user :vote/event ]
:db/cardinality :db.cardinality/one
:db/unique :db.unique/identity}
The way I imagine it, if I vote "agree" to the statement "roses are red" a new vote entity will be added with [:vote/value "agree"]
, then if I vote again "disagree" for the same statement (because I saw a white rose and changed my mind), the original entity will change the value of its :vote/value attribute to "disagree".
What I see instead is that each vote-value combination is treated as a different entity.
So I can vote 1 time "agree" and 1 time "disagree" for the same target with total of 2 votes per user.
How can I get this to work?Ok, looks like I need to use either the entity id or the tuple attribute to do this https://forum.datomic.com/t/db-unique-identity-does-not-work-for-tuple-attributes/1072 I will try that
...and there is a bug in datahike that prevents this specific approach, so I'll have to take a longer route https://github.com/replikativ/datahike/issues/510
Before tupleAttrs existed, it was common to solve this kind of problem with a custom transaction function (that is linearized and can do an atomic query + insert/update).
I’ve done the same as you in the past.
(`user` has an opinion
about a proposal
)
See: https://github.com/hhucn/decide3/blob/master/src/main/decide/models/opinion/database.clj#L109
I queried for the vote first and then updated the value on the entity itself:
(defn update-vote
"Returns a transaction for a new vote value."
[user event new-value]
(if-some [vote (get-vote user event)]
[[:db/add (:db/id vote) :vote/value new-value]]
[#:vote{:user user, :event event, :value new-value}]))