Как в Datascript создать новый атрибут из значения другого?
Попытка создать новый атрибут, значение которого является результатом преобразования другого атрибута той же сущности. Итак, скажем, у меня есть база данных, в которой каждая сущность имеет атрибут:content
. Я хочу иметь дополнительный атрибут для каждой сущности с именем:transformed
значение которого является результатом применения функции f
к :content
. Как бы я сделал это идиоматично и эффективно? В настоящее время пытается сделать это, выполнив транзакцию и присвоив значение нового атрибута значению функции, примененной к запросу, для значения исходного атрибута для этой сущности.
Если это не очевидно, я новичок в Datalog и Datascript
(doseq [included-block-ds-id (vec (ds/q '[:find ?id
:where
[?id :block/included true]]
@conn))]
(let [content (first (first (vec (ds/q '[:find ?content
:where
[?included-block-ds-id :block/content ?content]]
@conn))))]
(ds/transact! conn [[:db/add (first included-block-ds-id)
:block/hiccup (block-content->hiccup
conn
content)]])))
1 ответ
В целом ваш код правильный, но не оптимален с точки зрения производительности. Вы можете использовать один запрос для получения всех пар id-контент. Затем создайте из них одну транзакцию, используяfor
. Затем сделайте все сразу.
(let [db @conn
id+content (ds/q '[:find ?id ?content
:where [?id :block/included true]
[?id :block/content ?content]]
db)
tx (for [[id content] id+content]
[:db/add id :block/hiccup (block-content->hiccup db content)])]
(ds/transact! conn tx))
Обратите внимание, что в целом неплохо взять неизменное значение вашей базы данных в какой-то момент времени, а затем выполнять все вычисления на его основе (например, при переходе к block-content->hiccup
функция). Передавайте conn только тогда, когда вам нужна функция для изменения db.
В этом случае он вам не нужен, но в целом, если вам нужно искать атрибуты только для одного объекта, гораздо эффективнее использовать ds/entity
вместо запроса:
(:block/content (d/entity db id))