Получить все поля из объекта Datomic
В разделе "Встроенный" документа Datomic Queries and Rules говорится:
Языки запросов, такие как SQL, ориентированы вокруг модели клиент-сервер где, в одном разговоре, вы будете иметь оба:
- Ответьте на свой основной вопрос, например. который купил носки в этом месяце.
- Восстановить любую дополнительную информацию, необходимую для отчетности и обработки, например. каковы их имена и адреса электронной почты.
Последнее на самом деле не вопрос, это просто механическая навигация к соответствующей информации.
В то время как я ценю, как ортогональность двух различных упомянутых аспектов соблюдается, я думаю, что мне часто нужно получить целую сущность, в зависимости от ее атрибутов.
Насколько я знаю, запросы обычно имеют такую форму:
(datomic.api/q '[:find ?name ?age ?email
:where
[?e :myapp/name ?name]
[?e :myapp/age ?age]
[?e :myapp/email ?email]]
(db conn))
Если бы я хотел получить объекты, у которых есть N атрибутов, я бы хотел, чтобы они перечисляли их все в каждом запросе, что кажется утомительным и подверженным ошибкам.
Как сообщить Datomic для получения объектов со всеми полями, в которых они были сохранены, без необходимости явно указывать их?
Ответы
Ответ 1
datomic.api/entity предоставляет такую функциональность.
У него просто есть gotcha, что возвращенная карта имеет собственное представление, которое скрывает все поля, но :db/id
. Можно получить доступ к этим полям, но для их печати требуется слияние карты с обычной картой Clojure.
Ответ 2
Наличие объекта (id) из запроса типа:
=> (def eid (d/q '[:find ?e :where [?e :myapp/name "Fred"]] (db conn)))
вы можете получить EntityMap:
=> (def ent (d/entity (db conn) (ffirst eid)))
чтобы вы могли получать доступ к полям/атрибутам без дополнительного запроса:
=> (seq ent)
;; ([:myapp/name "Fred"] [:myapp/age 16] [:myapp/email "[email protected]"])
однако сначала проще получить ключи:
=> (keys ent)
;; (:myapp/name :myapp/age :myapp/email)
Вы даже можете получить обратные ключи ( "внешние" атрибуты ref, указывающие на этот объект), используя следующий трюк:
=> (.touch ent)
=> (keys (.cache ent))
Ответ 3
Существует специальная функция datomic.api/touch, чтобы просто "коснуться" всех атрибутов объекта.
Объект, возвращаемый функцией entity, ленив, и значение атрибута возвращается только при доступе, < функция href= "http://docs.datomic.com/clojure/#datomic.api/touch" > touch с готовностью извлекает все атрибуты сущности.
Пример:
(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 "[email protected]", :user/password "xxxxxx", :db/id 17592186046433}
Ответ 4
Вы можете использовать pull
, чтобы получить все поля от сущности или даже только выбор. Используя '[*]
, поскольку шаблон для pull будет извлекать все поля
См. документация по pull и пояснения.
Чтобы получить все поля из объекта с id eid
, используйте:
(d/pull (db conn) '[*] eid)
Pull также может использоваться в запросах:
(datomic.api/q '[:find (pull ?e [*])
:where
[?e :myapp/name]
(db conn))
Ответ 5
Я не тестировал его, но если я правильно помню, вы можете просто поместить переменную в качестве имени атрибута
(datomic.api/q '[:find ?key ?value
:where
[?e ?key ?value]]
(db conn))