2016-09-11 2 views
1

Ich habe ein Schema wie folgt aus:Updating Wert mit Kardinalität viele

[{:db/id #db/id[:db.part/db] 
    :db/ident :person/name 
    :db/valueType :db.type/string 
    :db/cardinality :db.cardinality/one 
    :db/doc "A person's name" 
    :db.install/_attribute :db.part/db} 
{:db/id #db/id[:db.part/db] 
    :db/ident :person/roles 
    :db/valueType :db.type/keyword 
    :db/cardinality :db.cardinality/many 
    :db/doc "A person's role" 
    :db.install/_attribute :db.part/db}] 

und einen Code wie folgt aus:

;; insert new person 
(def new-id (-> (d/transact conn [{:db/id (d/tempid :db.part/user) 
            :person/name "foo" 
            :person/roles #{:admin}}]) 
       (:tempids) 
       (vals) 
       (first))) 

(defn get-roles 
    [db eid] 
    (d/q '[:find ?roles . 
     :in $ ?eid 
     :where [?eid :user/roles ?roles]])) 

(get-roles (d/db conn) new-id) ;; => [:admin] 

;; update a person 
(d/transact conn [{:db/id new-id 
        :person/roles #{:client}}]) 

(get-roles (d/db conn) new-id) ;; => [:admin :client] 

Es scheint das Standardverhalten auf es ist, es wird Assoc gerade die neue Wert.

Wie kann ich dieses Ergebnis zu erhalten, nachdem die Aktualisierung Transaktion tun:

(get-roles (d/db conn) new-id) ;; => [:client] 
+0

Wer von einem Link auf die Dokumentation wissen, wo dieses Verhalten erklärt? –

Antwort

1

wenn das, was Sie wollen, ist, um die Liste der Rollen auf einen neuen Wert (ein ‚absoluter‘ Betrieb ‚im Gegensatz„Reset“ Zu den 'relativen' Operationen des Hinzufügens oder Entfernens von Rollen müssen Sie eine Transaktionsfunktion verwenden, um einen Vergleich durchzuführen und die Werte zurückzuziehen, die benötigt werden.

Hier ist eine grundlegende generische Implementierung:

{:db/id (d/tempid :db.part/user), 
:db/ident :my.fns/reset-to-many, 
:db/fn 
(d/function 
    {:lang :clojure, 
    :requires '[[datomic.api :as d]], 
    :params '[db e attr new-vals], 
    :code 
    '(let [ent (or (d/entity db e) 
       (throw (ex-info "Entity not found" 
          {:e e :t (d/basis-t db)}))) 
      entid (:db/id ent) 
      old-vals (get ent attr)] 
     (into 
     [{:db/id (:db/id ent) 
      ;; adding the new values 
      attr new-vals}] 
     ;; retracting the old values 
     (comp 
      (remove (set new-vals)) 
      (map (fn [v] 
        [:db/retract entid attr v]))) 
     old-vals) 
     )})} 

;; Usage 
(d/transact conn [[:my.fns/reset-to-many new-id :person/roles #{:client}]]) 
Verwandte Themen