【问题标题】:Retrieve Most Recent Entity from Datomic从 Datomic 检索最新的实体
【发布时间】:2013-09-28 21:09:31
【问题描述】:

我对实体及其时间戳感兴趣。本质上,我想要一个按时间排序的实体列表。

为此,我编写了以下函数:

(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 惯用用法的人加入并升级我的范例?

【问题讨论】:

    标签: clojure datomic


    【解决方案1】:

    我对在名义上将时间理解为一流原则的数据库中添加额外时间戳的想法感到困扰,因此(在对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,然后使用此函数查找事务时间戳以供以后排序。

    【讨论】:

    • 值得注意的是,AFAIK,这为您提供了为实体断言 :post/title 的当前值的瞬间,而不是实体最后一次交易的主题。
    • 内存放不下数据怎么办?例如。例如,您想获取 5 个最近的实体,而不关心其他实体。
    【解决方案2】:

    没有比遍历事务更优雅的方法了。这就是为什么我更喜欢为时间戳设置一个单独的域特定属性,而不是依赖于 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"))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-11-07
      • 1970-01-01
      • 2014-04-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-09
      • 1970-01-01
      相关资源
      最近更新 更多