Fork me on GitHub
#datalog
<
2023-07-11
>
Oz14:07:36

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 appreciated

pithyless15:07:49

If I understood the question correctly, perhaps this gist can help? https://gist.github.com/vvvvalvalval/5547d8b46414b955c88f

Oz18:07:58

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?

Oz20:07:50

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

Oz21:07:27

...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

pithyless05:07:46

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).

👍 2
Oz15:07:09

Thank you, I will look into that

Björn Ebbinghaus21:08:55

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}]))

Oz19:08:28

Thank you, I've used the same solution eventually,although my code is a little hackier. My app's domain is very close to decide3 but taking a more atomistic approach :-] I can probably take some ideas from it 🙏