我对实体及其时间戳感兴趣。基本上,我想要一个按时间排序的实体列表。
为此,我编写了以下功能:
(defn return-posts
"grabs all posts from Datomic"
[]
(d/q '[:find ?title ?body ?slug
:where
[?e :post/title ?title]
[?e :post/slug ?slug]
[?e :post/body ?body]] (d/db connection)))
(defn get-postid-from-slug
[slug]
(d/q '[:find ?e
:in $ ?slug
:where [?e :post/slug ?slug]] (d/db connection) slug))
(defn get-post-timestamp
"given an entid, returns the most recent timestamp"
[entid]
(->
(d/q '[:find ?ts
:in $ ?e
:where
[?e _ _ _]
[?e :db/txInstant ?ts]] (d/db connection) entid)
(sort)
(reverse)
(first)))
我觉得必须是一个根深蒂固的黑客。
有人会更熟练地使用惯用的Datomic使用并升级我的范例吗?
答案 0 :(得分:8)
我对为数据库添加额外时间戳的想法感到困扰,该数据库名义上将时间理解为一流原则,因此(在考虑Ulrik Sandberg概述的方法之后)演变了以下功能:
(defn return-posts
"grabs all posts from Datomic"
[uri]
(d/q '[:find ?title ?body ?slug ?ts
:where
[?e :post/title ?title ?tx]
[?e :post/slug ?slug]
[?e :post/body ?body]
[?tx :db/txInstant ?ts]] (d/db (d/connect uri))))
在Datalog中,省略对事务ID本身的绑定是惯用的,因为我们通常不关心。在这种情况下,我们非常关心并且用August Lileaas的话说,希望“遍历交易”(在某些情况下我们需要创建帖子的时间,但对于这个应用程序,交易时间足以订购实体)。
这种方法的一个显着缺点是最近编辑的条目将在列表中出现。为此,我将在稍后做一些事情,以便在Datomic中首次出现博客标准的帖子历史。
总结一下: 我已经为每个“post”实体ID绑定了事务实体ID,然后使用此函数查找事务时间戳以供以后排序。
答案 1 :(得分:1)
除了遍历交易之外,没有比这更优雅的方法了。这就是为什么我更喜欢为时间戳设置单独的特定于域的属性,而不是依赖于Datomic的事务时间戳。这是必要的一个例子是合并:假设你有一个wiki,并且想要合并两个wiki页面。在这种情况下,您可能希望自己控制时间戳,而不是使用事务中的时间戳。
我希望拥有:created-at
和:changed-at
属性。当我处理新实体时:
[[:db/add tempid :post/slug "..."]
[:db/add tempid :post/title "A title"]
[:db/add tempid :created-at (java.util.Date.)]
[:db/add tempid :changed-at (java.util.Date.)]]
然后更新:
[[:db/add post-eid :post/title "An updated title"]
[:db/add post-eid :changed-at (java.util.Date.)]]
这样我所要做的就是读出实体的:created-at属性,该属性将准备好并在索引中等待。
(defmacro find-one-entity
"Returns entity when query matches, otherwise nil"
[q db & args]
`(when-let [eid# (ffirst (d/q ~q ~db ~@args))]
(d/entity ~db eid#)))
(defn find-post-by-slug
[db slug]
(find-one-entity
'[:find ?e
:in $ ?slug
:where
[?e :post/slug ?slug]]
db
slug))
;; Get timestamp
(:created-at (find-post-by-slug db "my-post-slug"))