Datomic aggregates usage

2019-07-23 03:19发布

I want to find persons with minimal age with next query

(d/q '[:find ?name (min ?age)
         :in [[?name ?age]]]
       [["John" 20]
        ["Bill" 25]
        ["Jack" 20]
        ["Steve" 28]
        ["Andrew" 30]])

But result is

[["Andrew" 30] ["Bill" 25] ["Jack" 20] ["John" 20] ["Steve" 28]]

How to do that?

3条回答
做个烂人
2楼-- · 2019-07-23 03:32

Instead of chaining the queries together, you could use a subquery (query call from within the query instead of outside of it):

(d/q '[:find ?name ?mage
       :in $
       :where [(datomic.api/q '[:find (min ?age)
                                :where [_ :age ?age]]
                              $) [[?mage]]]
              [?name :age ?mage]]
   [["John" :age 20]
    ["Bill" :age 25]
    ["Jack" :age 20]
    ["Steve" :age 28]
    ["Andrew" :age 30]])

Returns:

#{["John" 20] ["Jack" 20]}
查看更多
家丑人穷心不美
3楼-- · 2019-07-23 03:43

This would be a pure Datalog solution

(let [db [["John" 20]
          ["Bill" 25]
          ["Jack" 20]
          ["Steve" 28]
          ["Andrew" 30]]]
  (d/q '[:find ?name ?min-age
         :in $ ?min-age
         :where [?name ?min-age]]
       db
       (ffirst (d/q '[:find (min ?age)
                      :in [[?name ?age]]]
                 db))))

A HAVING clause like in SQL is not part of the query language, but since all queries are executed in the peer, there is no overhead in doing nested queries.

查看更多
Bombasti
4楼-- · 2019-07-23 03:46

You don't need datomic in this case, as you already have in your sequence all the data needed. Use clojure sort instead.

(first (sort-by second [...]))
查看更多
登录 后发表回答