1

So basically i have a list of orders, a list of order providers and a list of users Each order has a property, :order/subscribers, which is a vector of zero or more subscribers. I would like to get the count of subscribers for order.

The query below give me only the orders with 1 or more subscribers, but need the orders with 0 subscribers as well

basically i'm getting this:

([4 "Provider1" "images/p1-logo.png" "orange" #inst "1970-01-01T00:00:00.000-00:00" 2] 
[7 "Provider2" "images/p2-logo.png" "red" #inst "1970-01-01T00:00:00.001-00:00" 1])

And would like to get this:

([4 "Provider1" "images/p1-logo.png" "orange" #inst "1970-01-01T00:00:00.000-00:00" 2]
[7 "Provider2" "images/p2-logo.png" "red" #inst "1970-01-01T00:00:00.001-00:00" 1]
[8 "Provider3" "images/p3-logo.png" "green" #inst "1970-01-01T00:00:00.001-00:00" 0])

This is the query and the schema i'm using.

Not sure if i should add some sample data as well.

 [:find ?ord ?name ?image ?color ?deadline (count ?subscribers)
        :where [?ord :order/provider ?pid]
               [?pid :provider/name ?name]
               [?pid :provider/image-url ?image]
               [?pid :provider/color ?color]
               [?ord :order/deadline ?deadline]
               [?ord :order/subscribers ?subscribers]]

(def schema {:order/provider    {:db/valueType :db.type/ref}
             :order/subscribers {:db/valueType :db.type/ref
                                 :db/cardinality :db.cardinality/many}})

Cheers and Thx in advance :)

akond
  • 15,865
  • 4
  • 35
  • 55
boogie666
  • 650
  • 10
  • 24

1 Answers1

2

You need to use functions to get attribute value. Here, get-else gets attribute value (a set in case of :db.cardinality/many) and then second function is used to get a count. Note that count fn is passed as an additional input. Also note that count in :find is a completely different beast — it’s an aggregation directive for datalog engine, but count we pass in input is just a regular Clojure count.

(d/q '[:find ?ord ?name ?image ?color ?deadline ?sc
       :in $ ?count
       :where [?ord :order/provider ?pid]
              [?pid :provider/name ?name]
              [?pid :provider/image-url ?image]
              [?pid :provider/color ?color]
              [?ord :order/deadline ?deadline]
              [(get-else $ ?ord :order/subscribers nil) ?subscribers]
              [(?count ?subscribers) ?sc]]
     db count)

Alternatively, you can just pass in the fn that does attribute fetch and count at the same time:

(d/q '[:find ?ord ?name ?image ?color ?deadline ?sc
       :in $ ?subscribers-count
       :where [?ord :order/provider ?pid]
              [?pid :provider/name ?name]
              [?pid :provider/image-url ?image]
              [?pid :provider/color ?color]
              [?ord :order/deadline ?deadline]
              [(?subscribers-count $ ?ord) ?sc]]
     db (fn [db ord] (count (:order/subscribers (d/entity db ord)))))

Hope that helps!

Niki Tonsky
  • 1,327
  • 11
  • 19