Question

The 'Embedded' section of the Datomic Queries and Rules document says:

Query languages like SQL are oriented around a client-server model where, in a single conversaton, you are going to have to both:

  • Answer your fundamental question, e.g. who bought socks this month.
  • Recover any additional information required for reporting and processing, e.g. what are their names and email addresses.

The latter is not really a query, it is just a mechanical navigation to related information.

While I appreciate how the orthogonality of the two different mentioned aspects is honored, I think I'll often need to retrieve a whole entity, whichever its attributes are.

As far as I know, queries typically have this form:

(datomic.api/q '[:find ?name ?age ?email
                 :where
                 [?e :myapp/name ?name]
                 [?e :myapp/age ?age]
                 [?e :myapp/email ?email]]
               (db conn))

If I wanted to retrieve entities that have N attributes, I'd have them to list them all in each query, which seems tedious and error-prone to me.

How to tell Datomic to retrieve the entities with all the fields they were persisted with, without having to specify them explicitly?

Was it helpful?

Solution 4

datomic.api/entity provides such functionality.

It just has the gotcha that the returned map has a custom representation which hides all fields but :db/id. One can access those fields, but printing them requires merging the map into a regular Clojure map.

OTHER TIPS

Having the entity (id) from query like:

=> (def eid (d/q '[:find ?e :where [?e :myapp/name "Fred"]] (db conn)))

you can get the EntityMap:

=> (def ent (d/entity (db conn) (ffirst eid)))

so you can access fields/attributes without making additional query:

=> (seq ent)
;; ([:myapp/name "Fred"] [:myapp/age 16] [:myapp/email "fred@email.com"])

however it may be easier to get the keys first:

=> (keys ent)
;; (:myapp/name :myapp/age :myapp/email)

You can even get reverse keys ("foreign" ref attributes that point to this entity) using the following trick:

=> (.touch ent)
=> (keys (.cache ent))

You can use pull to get all fields from an entity, or even just a selection. Using '[*] as the pattern for pull will retrieve all fields

See the pull documentation for more information.

To get all fields from an entity with id eid use:

(d/pull (db conn) '[*] eid)

Pull can also be used in queries:

(datomic.api/q '[:find (pull ?e [*])
                 :where
                 [?e :myapp/name]
               (db conn))

datomic.api/touch function

There is a specific datomic.api/touch function to just "Touch" all the attributes of the entity. Entity returned by the entity function are lazy and the attribute value is returned only when accessed, the touch function eagerly retrieve all the entity attributes.

Example:

(let [entity (d/entity db-val (ffirst (d/q '[:find ?e :in $ ?email
                                             :where [?e :user/email ?email]]
                                            db-val email))]
    ;;then just d/touch the entity returned by the d/entity fn
    (d/touch entity))
=> {:user/username "gretchen", :user/email "gretchen@user.com", :user/password "xxxxxx", :db/id 17592186046433}

I haven't tested it, but if I remember correctly you can just put a variable as the attribute name

(datomic.api/q '[:find ?key ?value
             :where
             [?e ?key ?value]]
           (db conn))
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top