When passed 2 rels, returns the rel corresponding to the natural join. When passed an additional keymap, joins on the corresponding keys.
;; This simple example shows each element of the first relation joined ;; with each element of the second (because they have no columns in common): user=> (def first-relation #{ {:a 1} {:a 2} }) user=> (def second-relation #{ {:b 1} {:b 2} }) user=> (join first-relation second-relation) #{{:b 1, :a 1} {:b 2, :a 1} {:b 1, :a 2} {:b 2, :a 2}} ;; Here's a larger example, in which a relation mainly about animal ownership ;; is joined with a relation about animal personality. The join is used to ;; produce a relation joining information about an animal's personality to ;; that animal. user=> (def animals #{{:name "betsy" :owner "brian" :kind "cow"} {:name "jake" :owner "brian" :kind "horse"} {:name "josie" :owner "dawn" :kind "cow"}}) user=> (def personalities #{{:kind "cow" :personality "stoic"} {:kind "horse" :personality "skittish"}}) #'user/personalities user=> (join animals personalities) #{{:owner "dawn", :name "josie", :kind "cow", :personality "stoic"} {:owner "brian", :name "betsy", :kind "cow", :personality "stoic"} {:owner "brian", :name "jake", :kind "horse", :personality "skittish"}} ;; (If cows had two personalities, instead of one, each cow would have ;; two rows in the output.) ;; Suppose `personalities` used `:species` instead of `:kind`: user=> (def personalities #{{:species "cow" :personality "stoic"} {:species "horse" :personality "skittish"}}) ;; A simple join would produce results like this: user=> (join animals personalities) #{{:kind "horse", :owner "brian", :name "jake", :species "cow", :personality "stoic"} {:kind "cow", :owner "dawn", :name "josie", :species "cow", :personality "stoic"} {:kind "horse", :owner "brian", :name "jake", :species "horse", :personality "skittish"} {:kind "cow", :owner "brian", :name "betsy", :species "cow", :personality "stoic"} {:kind "cow", :owner "dawn", :name "josie", :species "horse", :personality "skittish"} {:kind "cow", :owner "brian", :name "betsy", :species "horse", :personality "skittish"}} ;; Notice that "Jake" is both a horse and a cow in the first line. That's ;; likely not what you want. You can tell `join` to only produce output ;; where the `:kind` value is the same as the `:species` value like this: user=> (join animals personalities {:kind :species}) #{{:kind "cow", :owner "dawn", :name "josie", :species "cow", :personality "stoic"} {:kind "horse", :owner "brian", :name "jake", :species "horse", :personality "skittish"} {:kind "cow", :owner "brian", :name "betsy", :species "cow", :personality "stoic"}} ;; Notice that the `:kind` and `:species` keys both appear in each output map.
;; If you don't specify `km`, `join` has to 'guess' on which attributes to join. ;; Sometimes, result may surprise you: user=> (join [{:a 1 :b 2}] [{:c 3 :d 4} {:a 5 :b 6}]) ;#{{:a 5, :b 6} {:a 1, :b 2, :c 3, :d 4}}
;; join with rename of (otherwise clashing) keys. Note that in the following ;; relations, we have "user.type" and "account.type" (def users #{{:user-id 1 :name "john" :age 22 :type "personal"} {:user-id 2 :name "jake" :age 28 :type "company"} {:user-id 3 :name "amanda" :age 63 :type "personal"}}) (def accounts #{{:acc-id 1 :user-id 1 :amount 300.45 :type "saving"} {:acc-id 2 :user-id 2 :amount 1200.0 :type "saving"} {:acc-id 3 :user-id 1 :amount 850.1 :type "debit"}}) (require '[clojure.set :as s]) ;; Clojure equivalent of the SQL: ;; SELECT users.user-id, accounts.acc-id, ;; users.type as type, accounts.type as atype ;; FROM users ;; INNER JOIN accounts ON users.user-id = accounts.user-id; (s/project (s/join users (s/rename accounts {:type :atype})) [:user-id :acc-id :type :atype]) ;; #{{:user-id 1, :acc-id 1, :type "personal", :atype "saving"} ;; {:user-id 2, :acc-id 2, :type "company", :atype "saving"} ;; {:user-id 1, :acc-id 3, :type "personal", :atype "debit"}}
Returns a rel of the maps in xrel with the keys in kmap renamed to the vals in kmap
join