Get all fields from a Datomic entity

老子叫甜甜 提交于 2019-12-03 05:41:47

问题


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?


回答1:


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



回答2:


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



回答3:


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}



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




回答5:


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


来源:https://stackoverflow.com/questions/14189647/get-all-fields-from-a-datomic-entity

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!