Как в 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)]])))

person TomLisankie    schedule 26.05.2020    source источник


Ответы (1)


В целом ваш код правильный, но не оптимальный с точки зрения производительности. Вы можете использовать один запрос для получения всех пар id-content. Затем создайте из них одну транзакцию, используя 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 только тогда, когда вам нужна функция для изменения базы данных.

В данном случае он вам не нужен, но в целом, если вам нужно искать атрибуты только одной сущности, гораздо эффективнее использовать ds/entity вместо запроса:

(:block/content (d/entity db id))
person Nikita Prokopov    schedule 27.05.2020
comment
Это имеет больше смысла, но я все еще получаю StackOverflowError всякий раз, когда пытаюсь запросить базу данных для вновь созданного :block/hiccup для любого из объектов. Вот трассировка стека: pastebin.com/wEnmvW6e Кстати, эта же ошибка возникает при использовании (:block/hiccup (ds/entity db id)). - person TomLisankie; 28.05.2020
comment
что возвращает (block-content->hiccup db content)? из stacktrace кажется, что вы каким-то образом помещаете базу данных в базу данных - person Nikita Prokopov; 29.05.2020
comment
Боже мой... Похоже, я звонил (block-content-›hiccup conn content) вместо (block-content-›hiccup content conn). Я предполагаю, что мой мозг увидел, что оба начинаются с аферы и идут да, эта афера, поместите это здесь. На данный момент у меня была только функция идентификации для любого переданного контента. Но поскольку я случайно перепутал аргументы, контентом была вся база данных. ????‍♂️ напишите свои :предусловия, друзья - person TomLisankie; 29.05.2020