public
Last active

Datomic queries against Clojure collections

  • Download Gist
gistfile1.clj
Clojure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
;; Datomic example code
(use '[datomic.api :only (db q) :as d])
 
;; ?answer binds a scalar
(q '[:find ?answer :in ?answer]
42)
 
;; of course you can bind more than one of anything
(q '[:find ?last ?first :in ?last ?first]
"Doe" "John")
 
;; [?last ?first] binds a tuple
(q '[:find ?last ?first :in [?last ?first]]
["Doe" "John"])
 
;; [?first ...] binds a collection
(q '[:find ?first
:in [?first ...]]
["John" "Jane" "Phineas"])
 
;; [[?first ?last]] binds a relation
(q '[:find ?first
:in [[?first ?last]]]
[["John" "Doe"]
["Jane" "Doe"]])
 
;; a database binding name starts with $ instead of ?
;; any relation with 4-tuples E/A/V/T can act as a database
;; so in Datomic, you can mock a database with a list of lists
(q '[:find ?first
:in $db
:where [$db _ :firstName ?first]]
[[1 :firstName "John"]])
 
;; same as previous, but omit $db for single-database query
;; any relation with 4-tuples eavt can act as a database
(q '[:find ?first
:where [_ :firstName ?first]]
[[1 :firstName "John" 42]
[1 :lastName "Doe" 42]])
 
;; simple in-memory join, two tuple bindings
(q '[:find ?first ?height
:in [?last ?first ?email] [?email ?height]]
["Doe" "John" "jdoe@example.com"]
["jdoe@example.com" 71])
 
;; simple in-memory join, two relation bindings
;; see next example for a faster approach
(q '[:find ?first ?height
:in [[?last ?first ?email]] [[?email ?height]]]
[["Doe" "John" "jdoe@example.com"]
["Doe" "Jane" "jane@example.com"]]
[["jane@example.com" 73]
["jdoe@example.com" 71]])
 
;; same as previous example, but with database expressions
;; runs faster than relation bindings (as of July 2012)
(q '[:find ?first ?height
:in $a $b
:where [$a ?last ?first ?email]
[$b ?email ?height]]
[["Doe" "John" "jdoe@example.com"]
["Doe" "Jane" "jane@example.com"]]
[["jane@example.com" 73]
["jdoe@example.com" 71]])
 
;; simple in-memory join, two database bindings
(q '[:find ?first ?height
:in $db1 $db2
:where [$db1 ?e1 :firstName ?first]
[$db1 ?e1 :email ?email]
[$db2 ?e2 :email ?email]
[$db2 ?e2 :height ?height]]
[[1 :firstName "John"]
[1 :email "jdoe@example.com"]
[2 :firstName "Jane"]
[2 :email "jane@example.com"]]
[[100 :email "jane@example.com"]
[100 :height 73]
[101 :email "jdoe@example.com"]
[101 :height 71]])
 
;; compare to http://stackoverflow.com/questions/3717939/iterating-and-processing-an-arraylist
(q '[:find ?car ?speed
:in [[?car ?speed]]
:where [(> ?speed 100)]]
[["Stock" 225]
["Spud" 80]
["Rocket" 400]
["Stock" 225]
["Clunker" 40]])
 
;; compare to http://stackoverflow.com/questions/109383/how-to-sort-a-mapkey-value-on-the-values-in-java
(->> (q '[:find ?k ?v
:in [[?k ?v] ...]]
{:D 67.3 :A 99.5 :B 67.4 :C 67.5})
(sort-by second))

The age of the question-mark prefixed symbol in Clojure is nigh!

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.