Getting the id of an inserted entity in datomic?

2020-07-03 06:57发布

问题:

After I run a transaction in datomic to insert a value, how I can use the return value of the transaction to get the ids of any entities that were created?

Here is a sample of the return value I get after an insert:

#<promise$settable_future$reify__4841@7c92b2e9: {:db-before datomic.db.Db@62d0401f, :db-after datomic.db.Db@bba61dfc,
 :tx-data [#Datum{:e 13194139534331 :a 50 
:v #inst "2013-06-19T11:38:08.025-00:00" 
:tx 13194139534331 :added true} #Datum{:e 17592186045436 .....

I can see the underlying datums...how can I extract their values?

回答1:

Use d/resolve-tempid. If you were to transact a single entity, looking at :tx-data would work but if your transaction contained more than one entity, then you wouldn't know the order in which they appear in :tx-data.

What you should do is give temporary ids to your entities (before transacting them) using either (d/tempid) or its literal representation #db/id[:db.part/user _negativeId_] and then use d/resolve-tempid to go from your temporary id to the real id given by the database. The code would look something like:

(d/resolve-tempid (d/db conn) (:tempids tx) (d/tempid :db.part/user _negativeId_))

For a full code sample, see this gist.



回答2:

Ah, figured it out.

I had to deref the Clojure promise, and then I was able to yank out the values I wanted:

 (:e (second (:tx-data @(transact! conn query))))


回答3:

Wrote a quick function based on a2ndrade's answer. The naming isn't ideal and I may be committing idiomatic faux pas; suggestions are very much welcome.

(ns my.datomic.util
  (:require [datomic.api :as d]))

(defn transact-and-get-id
  "Transact tx and return entity id."
  [conn tx]
  (let [tempid (:db/id tx)
        post-tx @(d/transact conn [tx])
        db (:db-after post-tx)
        entid (d/resolve-tempid db (:tempids post-tx) tempid)]
    entid))

Example usage:

(def my-conn
  (d/connect (str "datomic:sql://datomic?jdbc:postgresql://"
                  "127.0.1:5432/datomic?user=datomic&password=somepw")

(defn thing-tx
  "Create transaction for new thing."
  [name]
  {:db/id (d/tempid :db.part/user)
   :thing/name name})

(transact-and-get-id my-conn (thing-tx "Bob")) ;; => 17592186045502


回答4:

The Tupelo Datomic library has a function (td/eids tx-result) to easily extract the EIDs created in a transaction. For example:

  ; Create Honey Rider and add her to the :people partition
  (let [tx-result   @(td/transact *conn* 
                        (td/new-entity :people ; <- partition is first arg (optional) to td/new-entity 
                          { :person/name "Honey Rider" :location "Caribbean" :weapon/type #{:weapon/knife} } ))
        [honey-eid]  (td/eids tx-result)  ; retrieve Honey Rider's EID from the seq (destructuring)
  ]