DataScript<-->Datomic数据同步
Table of Contents
新的方法
目前能想到的方法是拿到 tx-report
的时候, 查询两次, 一次查询 db-after
, 一次查询 db-before
.
如果直接查询全量数据, 涉及到的范围会非常大. 但是datomic支持指定多个数据源.
假设有一个查询是这样的逻辑:
(d/q '[:find [(pull ?e [:db/id :message/content {:message/from [:user/nickname] :message/to [:user/nickname]}]) ...] :where [?e :message/content] [?e :message/to ?u] [?e :message/from ?from] [?u :user/nickname "dog"] [?u :user/friends ?from]] (d/db conn))
这个查询, 查询一个名叫dog的用户, 收到的所有来自于他的好友, 并发送给他的信息. 这种查询的结果, 在两种情况下会发生变化.
- 产生了新的符合条件的信息
- dog的好友列表, 发生了变化.
监听 tx-report-queue
, 我们可以得到四个比较重要的东西.
db-before
事务发生之前的数据库db-after
事务发生之后的数据库tx-data
事务的所有datom, 本身也是一个数据源tempids
事务中新增数据的entity id
一种查询方法(不能解决所有问题)
(d/q '[:find [(pull ?e [:db/id :message/content {:message/from [:user/nickname] :message/to [:user/nickname]}]) ...] :in $ $tx-data :where [$tx-data ?u] [$ ?e :message/to ?u] [$ ?e :message/from ?from] [$ ?u :user/nickname "dog"] [$ ?u :user/friends ?from]] db tx-data)
假设用户列表发生变化, 我们用这个查询查询两次, 一次db为 db-before
, 一次db为 db-after
.
然后对比得到的数据, 我们就得到了之前的查询结果的增量变化(新增或减少数据).
如果不考虑数据的减少, 那么还是可以用下面的方法.
这种方式只能增量同步
数据结构
消息有:message/to和:message/content, 用户有:user/nickname. :message/to是ref类型, 指向用户的entity-id
数据的查询
(d/q '[:find [(pull ?e [*]) ...] :in $ ?n :where [?e :message/to ?u] [?u :user/nickname ?n]] (d/db conn) "dog")
数据的更新
(def tx-data [[1321867981 :message/to 1236782618 1283768726 true] [1321867981 :message/content "dog" 1283768726 true]]) (d/q '[:find [(pull ?e [*]) ...] :in $ $tx-data ?n :where [$tx-data ?e] [$ ?e :message/to ?u] [$ ?u :user/nickname ?n]] db-after tx-data "dog")
流程
- 客户端UI组件加载时, 向服务器和DataScript(还没有数据)发起查询. 查询语句需要是pull风格的.
- 服务器通过pull的查询, 查出来需要的entity, 直接返回给客户端. 客户端不需要将entity拆分成tx, 直接合并到DataScript即可.
- 监听tx-report-queue, 或者新发生transaction的tx-data和db-after, 在原有查询的基础上组合新的查询. 可以查询到所有受到影响的entity.
- 把受到影响的entity推送给客户端.
- 服务器推送的数据, 客户端UI组件重绘.