Last active
August 29, 2015 14:15
-
-
Save vvvvalvalval/c3d9bae9a003852a1acc to your computer and use it in GitHub Desktop.
'populate foreign keys' functionality with Monger, emulates a subset of Mongoose's populate
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(require '[monger.collection :as mc]) | |
(require '[monger.operators :as mop]) | |
(defn populate "Populates the given docs sequence by looking up the 'foreign key' as an :_id in `foreign-coll`. | |
`foreign-path` can be either a single key or a sequence of keys (as in get-in) | |
Assumes the foreign keys are ObjectIds or coercable to objectIds. | |
Returns a seq of the docs where the foreign keys have been updated to be the foreign documents, in the same order. | |
" | |
[foreign-coll foreign-path docs] | |
(let [foreign-path (if (sequential? foreign-path) foreign-path [foreign-path]) ;; convert path to a seq if it's not one | |
foreign-keys (->> docs (map #(get-in % foreign-path)) (filter some?) set) ;; the set of foreign keys to pre-fetch | |
foreign-docs (->> (mc/find-maps foreign-coll {:_id {mop/$in foreign-keys}}) ;; fetch the foreign keys and keep a map foreign-key -> foreign-doc | |
(reduce (fn [m {:keys [_id] :as fd}] (assoc m _id fd)) {}))] | |
(->> docs (map #(update-in % foreign-path foreign-docs))) ;; replace foreign key with foreign doc in each document | |
)) | |
(comment "Example" | |
(def movies-coll "movies") | |
(def people-coll "people") | |
;; without populate. | |
;; Documents in the "movies" collection have a 'foreign key' to documents in the "people" collection. | |
(mc/find-maps movies-coll) | |
=> ({:_id "54d34ffbd4c6b26ee3db8a28", | |
:title "2001: A Space Odyssey", | |
:staff {:director "546f2ac50e73c602001b97ee"}}, | |
{:_id "54d34ffbd4c6b26ee3db8a2c", | |
:title "Gladiator", | |
:staff {:director "5475b212cad31102007a562e"}} | |
{:_id "54d34ffbd4c6b26ee3db8a2e", | |
:title "The Lord of the Rings", | |
:staff {:director "548b28c6df8b39030021e36c"}}) | |
;; with populate. | |
(->> (mc/find-maps movies-coll) | |
(populate people-coll [:staff :director])) | |
=> ({:_id "54d34ffbd4c6b26ee3db8a28", | |
:title "2001: A Space Odyssey", | |
:staff {:director {:_id "546f2ac50e73c602001b97ee", | |
:firstName "Stanley", :lastName "Kubrick"}}}, | |
{:_id "54d34ffbd4c6b26ee3db8a2c", | |
:title "Gladiator", | |
:staff {:director {:_id "5475b212cad31102007a562e" | |
:firstName "Ridley", :lastName "Scott"}}} | |
{:_id "54d34ffbd4c6b26ee3db8a2e", | |
:title "The Lord of the Rings", | |
:staff {:director {:_id "548b28c6df8b39030021e36c" | |
:firstName "Peter", :lastName "Jackson"}}}) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment