Fork me on GitHub
#datascript
<
2023-01-02
>
Brandon Olivier21:01:14

Is there a way to upsert on a list? A simplified version of my schema is

(def conn (d/create-conn
           {:location/name  {:db/cardinality :db.cardinality/one
                             :db/unique      :db.unique/identity}
            :location/goods {:db/valueType   :db.type/ref
                             :db/cardinality :db.cardinality/many}

            :symbol {}
            :price  {}}))
and the problem I'm having is that when I update location (to reflect price changes), the new symbol/price entities are appended to the list instead of updated.

Brandon Olivier21:01:41

An example of what I mean

(ns datascript-example
  (:require [datascript.core :as d]))

(def conn (d/create-conn
           {:location/name  {:db/cardinality :db.cardinality/one
                             :db/unique      :db.unique/identity}
            :location/goods {:db/valueType   :db.type/ref
                             :db/cardinality :db.cardinality/many}

            :symbol {}
            :price  {}}))

(d/transact! conn
             [{:location/name "New York City"
               :location/goods [{:symbol "Cheese"
                                 :price 10}
                                {:symbol "Chocolate"
                                 :price 2}]}])

(ffirst (d/q '[:find (count ?e)
               :where [?e]] @conn))
Everytime the transaction is run, the count increases by 2, when imo it should stay the same.

lilactown22:01:55

you declare :location/goods a ref type but :symbol is not unique

Brandon Olivier22:01:43

symbol isn't unique because different locations can have the same goods in their list of goods, but the prices need to be different

Brandon Olivier22:01:33

I considered duplicating :location/name on the goods and setting that to be unique but that duplication seems wrong to me

lilactown22:01:10

then instead of a vector, could you use a set?

lilactown22:01:35

you won't be able to update the price, though

Brandon Olivier22:01:21

I'll need a unique attribute to update the price, then?

lilactown22:01:47

maybe a hash map

{:location/name "New York City"
 :location/goods {"Cheese" {:price 10}}}

lilactown22:01:50

idk what your queries are like though

Brandon Olivier22:01:25

I did a quick test, and I can generate a unique attribute with [symbol location/name] which seems to make the updates work as expected

Niki14:01:17

Make :goods/location instead of :location/goods, and then create a tuple of :goods/location + :goods/symbol and mark that unique