查找:db / txInstant最接近Datomic中属性中定义的日期?

时间:2016-10-06 10:06:49

标签: clojure datomic

我们说我有以下Datomic架构:

; --- e1
{:db/id                 #db/id[:db.part/db]
 :db/ident              :e1/guid
 :db/unique             :db.unique/identity
 :db/valueType          :db.type/string
 :db/cardinality        :db.cardinality/one
 :db.install/_attribute :db.part/db}
{:db/id                 #db/id[:db.part/db]
 :db/ident              :e1/createdAt
 :db/valueType          :db.type/instant
 :db/cardinality        :db.cardinality/one
 :db.install/_attribute :db.part/db}
{:db/id                 #db/id[:db.part/db]
 :db/ident              :e1/e2s
 :db/valueType          :db.type/ref
 :db/cardinality        :db.cardinality/many
 :db.install/_attribute :db.part/db}
 ..

; --- e2
{:db/id                 #db/id[:db.part/db]
 :db/ident              :e2/guid
 :db/valueType          :db.type/string
 :db/cardinality        :db.cardinality/one
 :db/unique             :db.unique/identity
 :db.install/_attribute :db.part/db}
{:db/id                 #db/id[:db.part/db]
 :db/ident              :e2/startedAt
 :db/valueType          :db.type/instant
 :db/cardinality        :db.cardinality/one
 :db.install/_attribute :db.part/db}
{:db/id                 #db/id[:db.part/db]
 :db/ident              :e2/stoppedAt
 :db/valueType          :db.type/instant
 :db/cardinality        :db.cardinality/one
 :db.install/_attribute :db.part/db}
 ..

我想找到对e1 所做的 last 交易的:db/txInstant到与e1相关联的任何e2,其中e1' s :e1/createdAt或e2' :e2/startedAt:e2/stoppedAt小于或等于提供的日期(#inst)。如何在Datomic中构造这样的查询?

1 个答案:

答案 0 :(得分:1)

您可以查询"历史" " max"的数据库交易时间符合您定义的标准。如果需要,您还可以检查哪个属性从?attr更改。

(d/transact conn [{:db/id        (d/tempid :db.part/user)
                   :e1/guid      (str (d/squuid))
                   :e1/createdAt #inst "2016-10-21"
                   :e1/e2s       [{:db/id        (d/tempid :db.part/user)
                                   :e2/guid      (str (d/squuid))
                                   :e2/startedAt #inst "2016-10-23"
                                   :e2/stoppedAt #inst "2016-10-25"}]}])


(d/q '[:find (max ?inst)
       :in $ ?d
       :where
       [?e1 :e1/createdAt ?create]
       [?e1 :e1/e2s ?e2]
       [?e2 :e2/startedAt ?start]
       [?e2 :e2/stoppedAt ?stop]
       [(compare ?d ?create) ?c1]
       [(compare ?d ?start) ?c2]
       [(compare ?d ?stop) ?c3]
       (not [(pos? ?c1)] [(pos? ?c2)] [(pos? ?c3)])
       [?e1 ?attr _ ?tx]
       [?tx :db/txInstant ?inst]]
     (d/history (d/db conn))
     #inst "2016-10-24")

2016-10-24将为您提供#inst来处理您的数据。 2016-10-26什么都不给你。

<强> 更新:

请允许我通过以下方式更改架构:

1)将e1和e2重命名为&#34; task&#34;任务(e1)可以有多个子任务(e2)

2)在事务本身中保留所有时间戳(即createdAt,startedAt,stoppedAt在tx中都变为txInstant)。

通过此更改,查询只是在给定瞬间(?tc)时找到最接近(最大)的e1和/或e2(任务及其子任务)的txInstant。

(q '[:find (max ?t) .
     :in $ ?e ?tc
     :where
     (or-join [?tx]
              ;; parent task created
              [?e :task/name _ ?tx]
              ;; subtask started or stopped
              (and [?e :task/subtask ?s]
                   [?s _ _ ?tx]))
     [?tx :db/txInstant ?t]
     [(compare ?tc ?t) ?x]
     [(>= ?x 0)]]
   (d/history (db conn))
   parent-task1
   #inst "2016-10-26")

示例场景:

@(d/transact conn [{:db/id                 #db/id[:db.part/db]
                    :db/ident              :task/name
                    :db/valueType          :db.type/string
                    :db/cardinality        :db.cardinality/one
                    :db.install/_attribute :db.part/db}
                   {:db/id                 #db/id[:db.part/db]
                    :db/ident              :task/completed
                    :db/valueType          :db.type/boolean
                    :db/cardinality        :db.cardinality/one
                    :db.install/_attribute :db.part/db}
                   {:db/id                 #db/id[:db.part/db]
                    :db/ident              :task/subtask
                    :db/valueType          :db.type/ref
                    :db/cardinality        :db.cardinality/many
                    :db.install/_attribute :db.part/db}
                   {:db/id        #db/id[:db.part/tx]
                    :db/txInstant #inst "2016-01-01"}])

;; parent task created on 10-21
(let [p               (d/tempid :db.part/user -1)
      {tids :tempids} @(d/transact conn [{:db/id        #db/id [:db.part/tx]
                                          :db/txInstant #inst "2016-10-21"}
                                         [:db/add p :task/name "Parent Task"]])]
  (def parent-task1 (d/resolve-tempid (db conn) tids p)))

;; start a subtask on 10-23
(let [s               (d/tempid :db.part/user -2)
      {tids :tempids} @(d/transact conn [{:db/id        #db/id [:db.part/tx]
                                          :db/txInstant #inst "2016-10-23"}
                                         [:db/add s :task/name "subtask 1"]
                                         [:db/add parent-task1 :task/subtask  s]])]
  (def subtask1 (d/resolve-tempid (db conn) tids s)))

;; stop the subtask on 10-25
@(d/transact conn [{:db/id #db/id [:db.part/tx]
                    :db/txInstant #inst "2016-10-25"}
                   [:db/add subtask1 :task/completed true]])

有了这个,上面的查询将给出以下结果:

2016-10-20 => nil 
2016-10-21 => 2016-10-21 
2016-10-22 => 2016-10-21
2016-10-23 => 2016-10-23
2016-10-24 => 2016-10-23 
2016-10-25 => 2016-10-25 
2016-10-26 => 2016-10-25