在 Datascript 中,如何从另一个属性的值创建一个新属性?

In Datascript, how can I create a new attribute from the value of another?

正在尝试创建一个新属性,其中的值是对同一实体的不同属性进行转换的结果。所以,假设我有一个数据库,其中每个实体都有属性 :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)]])))

总的来说,您的代码是正确的,但在性能方面并不是最佳的。您可以使用单个查询来检索所有 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))