Datomic:如何在查询中跨任意数量的数据库进行查询?
Datomic: How do I query across any number of database inside of a query?
我正在使用 Datomic,并希望根据我的查询从任意数量的时间点提取整个实体。 Datomic 文档有一些不错的示例,说明如果我在执行查询之前知道这些实例,我可以如何从两个不同的数据库实例执行查询。但是,我希望我的查询能够确定我需要的 "as-of" 类型数据库实例的数量,然后在提取实体时使用这些实例。这是我目前所拥有的:
(defn pull-entities-at-change-points [entity-id]
(->>
(d/q
'[:find ?tx (pull ?dbs ?client [*])
:in $ [?dbs ...] ?client
:where
[?client ?attr-id ?value ?tx true]
[(datomic.api/ident $ ?attr-id) ?attr]
[(contains? #{:client/attr1 :client/attr2 :client/attr3} ?attr)]
[(datomic.api/tx->t ?tx) ?t]
[?tx :db/txInstant ?inst]]
(d/history (d/db db/conn))
(map #(d/as-of (d/db db/conn) %) [1009 1018])
entity-id)
(sort-by first)))
我试图找到所有交易,其中 :client
实体的某些属性发生了变化,然后提取该实体在这些时间点存在的状态。行:(map #(d/as-of (d/db db/conn) %) [1009 1018])
是我尝试在我知道客户端属性已更改的两个特定事务中创建一系列数据库实例。理想情况下,我想在一个查询中完成所有这些,但我不确定这是否可能。
希望这是有道理的,但如果您需要更多详细信息,请告诉我。
我会将拉取调用拆分为单独的 API 调用,而不是在查询中使用它们。我会将查询本身限制为获取感兴趣的交易。解决这个问题的一个示例解决方案是:
(defn pull-entities-at-change-points
[db eid]
(let
[hdb (d/history db)
txs (d/q '[:find [?tx ...]
:in $ [?attr ...] ?eid
:where
[?eid ?attr _ ?tx true]]
hdb
[:person/firstName :person/friends]
eid)
as-of-dbs (map #(d/as-of db %) txs)
pull-w-t (fn [as-of-db]
[(d/as-of-t as-of-db)
(d/pull as-of-db '[*] eid)])]
(map pull-w-t as-of-dbs)))
这个函数针对我用玩具模式构建的数据库会 return 结果如下:
([1010
{:db/id 17592186045418
:person/firstName "Gerry"
:person/friends [{:db/id 17592186045419} {:db/id 17592186045420}]}]
[1001
{:db/id 17592186045418
:person/firstName "Jerry"
:person/friends [{:db/id 17592186045419} {:db/id 17592186045420}]}])
我要评论的几点:
- 上面的函数采用 a database value 而不是从 ambient/global 连接获取数据库。
- 我们为每个不同的时间 t 映射拉力。
- using the pull API 作为入口点而不是查询适用于我们手头有实体和其他信息并且只需要属性或遍历引用的情况。
- 在一个大查询中完成所有事情的动力在 Datomic 中并不存在,因为相关段将在对等方的缓存中实现。你不是,也就是说,在使用一个查询时节省了一次往返。
- 集合绑定形式is preferred over
contains
and leverages query caching.
我正在使用 Datomic,并希望根据我的查询从任意数量的时间点提取整个实体。 Datomic 文档有一些不错的示例,说明如果我在执行查询之前知道这些实例,我可以如何从两个不同的数据库实例执行查询。但是,我希望我的查询能够确定我需要的 "as-of" 类型数据库实例的数量,然后在提取实体时使用这些实例。这是我目前所拥有的:
(defn pull-entities-at-change-points [entity-id]
(->>
(d/q
'[:find ?tx (pull ?dbs ?client [*])
:in $ [?dbs ...] ?client
:where
[?client ?attr-id ?value ?tx true]
[(datomic.api/ident $ ?attr-id) ?attr]
[(contains? #{:client/attr1 :client/attr2 :client/attr3} ?attr)]
[(datomic.api/tx->t ?tx) ?t]
[?tx :db/txInstant ?inst]]
(d/history (d/db db/conn))
(map #(d/as-of (d/db db/conn) %) [1009 1018])
entity-id)
(sort-by first)))
我试图找到所有交易,其中 :client
实体的某些属性发生了变化,然后提取该实体在这些时间点存在的状态。行:(map #(d/as-of (d/db db/conn) %) [1009 1018])
是我尝试在我知道客户端属性已更改的两个特定事务中创建一系列数据库实例。理想情况下,我想在一个查询中完成所有这些,但我不确定这是否可能。
希望这是有道理的,但如果您需要更多详细信息,请告诉我。
我会将拉取调用拆分为单独的 API 调用,而不是在查询中使用它们。我会将查询本身限制为获取感兴趣的交易。解决这个问题的一个示例解决方案是:
(defn pull-entities-at-change-points
[db eid]
(let
[hdb (d/history db)
txs (d/q '[:find [?tx ...]
:in $ [?attr ...] ?eid
:where
[?eid ?attr _ ?tx true]]
hdb
[:person/firstName :person/friends]
eid)
as-of-dbs (map #(d/as-of db %) txs)
pull-w-t (fn [as-of-db]
[(d/as-of-t as-of-db)
(d/pull as-of-db '[*] eid)])]
(map pull-w-t as-of-dbs)))
这个函数针对我用玩具模式构建的数据库会 return 结果如下:
([1010
{:db/id 17592186045418
:person/firstName "Gerry"
:person/friends [{:db/id 17592186045419} {:db/id 17592186045420}]}]
[1001
{:db/id 17592186045418
:person/firstName "Jerry"
:person/friends [{:db/id 17592186045419} {:db/id 17592186045420}]}])
我要评论的几点:
- 上面的函数采用 a database value 而不是从 ambient/global 连接获取数据库。
- 我们为每个不同的时间 t 映射拉力。
- using the pull API 作为入口点而不是查询适用于我们手头有实体和其他信息并且只需要属性或遍历引用的情况。
- 在一个大查询中完成所有事情的动力在 Datomic 中并不存在,因为相关段将在对等方的缓存中实现。你不是,也就是说,在使用一个查询时节省了一次往返。
- 集合绑定形式is preferred over
contains
and leverages query caching.