Получить все поля из объекта 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 извлекать объекты со всеми полями, с которыми они были сохранены, без необходимости указывать их явно?


person deprecated    schedule 07.01.2013    source источник


Ответы (5)


Имея объект (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))
person Grzegorz Luczywo    schedule 15.04.2013

Вы можете использовать pull, чтобы получить все поля из объекта или даже только выборку. Использование '[*] в качестве шаблона для извлечения извлечет все поля

Дополнительную информацию см. в документации по извлечению.

Чтобы получить все поля из объекта с идентификатором eid, используйте:

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

Pull также можно использовать в запросах:

(datomic.api/q '[:find (pull ?e [*])
                 :where
                 [?e :myapp/name]
               (db conn))
person ChrisBlom    schedule 03.09.2015
comment
Вам не нужно использовать _ в конечной позиции в предложении :where — эту позицию можно просто опустить. То есть, [?e :myapp/name]. - person Ben Kamphaus; 10.09.2015

datomic.api/touch

Существует специальная функция datomic.api/touch, которая просто "Прикоснитесь" ко всем атрибутам сущности. Объект, возвращенный entity являются ленивыми, и значение атрибута возвращается только при доступе, 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}
person Jérémie    schedule 29.12.2014

datomic.api/entity предоставляет такой функционал.

У него просто есть проблема, что возвращенная карта имеет собственное представление, которое скрывает все поля, кроме :db/id. Доступ к этим полям можно получить, но для их печати требуется объединить карту с обычной картой Clojure.

person deprecated    schedule 07.01.2013
comment
Пара замечаний: (1) сущности не скрывают атрибуты, они представляют собой ленивый интерфейс для получения атрибутов сущности и связанных сущностей. Это важно понимать с точки зрения производительности, и это объясняет, почему не все атрибуты видны сразу — чтобы отобразить атрибуты, необходимо получить данные из БД, что лишает преимущества лени. (2) Нет необходимости объединять объект с картой — просто вызовите touch для получения всех атрибутов. - person camdez; 17.03.2017

Я не проверял это, но если я правильно помню, вы можете просто указать переменную в качестве имени атрибута.

(datomic.api/q '[:find ?key ?value
             :where
             [?e ?key ?value]]
           (db conn))
person Joe Lehmann    schedule 07.01.2013
comment
Не уверен, что ваш запрос был просто заглушкой, но он выдает исключение IllegalArgumentException, поскольку это приведет к полному сканированию базы данных. - person deprecated; 07.01.2013
comment
Да, обычно вы ограничиваете объект, добавляя некоторые значимые предложения where, например, [?e :user/name Joe] - person Joe Lehmann; 09.01.2013