Merge branch 'map/reduce'
This commit is contained in:
commit
aee8862bc6
3 changed files with 91 additions and 13 deletions
|
|
@ -9,7 +9,9 @@
|
||||||
|
|
||||||
(ns monger.collection
|
(ns monger.collection
|
||||||
(:refer-clojure :exclude [find remove count drop])
|
(:refer-clojure :exclude [find remove count drop])
|
||||||
(:import (com.mongodb Mongo DB DBCollection WriteResult DBObject WriteConcern DBCursor) (java.util List Map) (clojure.lang IPersistentMap ISeq))
|
(:import [com.mongodb Mongo DB DBCollection WriteResult DBObject WriteConcern DBCursor MapReduceCommand MapReduceCommand$OutputType]
|
||||||
|
[java.util List Map]
|
||||||
|
[clojure.lang IPersistentMap ISeq])
|
||||||
(:require [monger core result])
|
(:require [monger core result])
|
||||||
(:use [monger.conversion]))
|
(:use [monger.conversion]))
|
||||||
|
|
||||||
|
|
@ -281,6 +283,20 @@
|
||||||
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* from)]
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* from)]
|
||||||
(.rename coll to drop-target))))
|
(.rename coll to drop-target))))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; Map/Reduce
|
||||||
|
;;
|
||||||
|
|
||||||
|
(defn map-reduce
|
||||||
|
([^String collection, ^String js-mapper, ^String js-reducer, ^String output, ^Map query]
|
||||||
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
||||||
|
(.mapReduce coll js-mapper js-reducer output (to-db-object query))))
|
||||||
|
([^String collection, ^String js-mapper, ^String js-reducer, ^String output, ^MapReduceCommand$OutputType output-type, ^Map query]
|
||||||
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
||||||
|
(.mapReduce coll js-mapper js-reducer output output-type (to-db-object query)))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; Implementation
|
;; Implementation
|
||||||
;;
|
;;
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@
|
||||||
;; You must not remove this notice, or any other, from this software.
|
;; You must not remove this notice, or any other, from this software.
|
||||||
|
|
||||||
(ns monger.result
|
(ns monger.result
|
||||||
(:import (com.mongodb DBObject WriteResult)
|
(:import [com.mongodb DBObject WriteResult MapReduceOutput]
|
||||||
(clojure.lang IPersistentMap))
|
[clojure.lang IPersistentMap])
|
||||||
(:require [monger conversion]))
|
(:require [monger conversion]))
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -46,4 +46,9 @@
|
||||||
(has-error? (.getLastError result)))
|
(has-error? (.getLastError result)))
|
||||||
(updated-existing?
|
(updated-existing?
|
||||||
[^WriteResult result]
|
[^WriteResult result]
|
||||||
(updated-existing? (.getLastError result))))
|
(updated-existing? (.getLastError result)))
|
||||||
|
|
||||||
|
MapReduceOutput
|
||||||
|
(ok?
|
||||||
|
[^MapReduceOutput result]
|
||||||
|
(ok? ^DBObject (.getRaw result))))
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
(set! *warn-on-reflection* true)
|
(set! *warn-on-reflection* true)
|
||||||
|
|
||||||
(ns monger.test.collection
|
(ns monger.test.collection
|
||||||
(:import [com.mongodb WriteResult WriteConcern DBCursor DBObject CommandResult$CommandFailure]
|
(:import [com.mongodb WriteResult WriteConcern DBCursor DBObject CommandResult$CommandFailure MapReduceOutput MapReduceCommand MapReduceCommand$OutputType]
|
||||||
[org.bson.types ObjectId]
|
[org.bson.types ObjectId]
|
||||||
[java.util Date])
|
[java.util Date])
|
||||||
(:require [monger core result util conversion]
|
(:require [monger core util]
|
||||||
[clojure stacktrace]
|
[clojure stacktrace]
|
||||||
[monger.collection :as mgcol])
|
[monger.collection :as mgcol]
|
||||||
|
[monger.result :as mgres]
|
||||||
|
[monger.conversion :as mgcnv])
|
||||||
(:use [clojure.test]))
|
(:use [clojure.test]))
|
||||||
|
|
||||||
(monger.core/connect!)
|
(monger.core/connect!)
|
||||||
|
|
@ -60,7 +62,7 @@
|
||||||
|
|
||||||
(deftest insert-a-basic-db-object-without-id-and-with-default-write-concern
|
(deftest insert-a-basic-db-object-without-id-and-with-default-write-concern
|
||||||
(let [collection "people"
|
(let [collection "people"
|
||||||
doc (monger.conversion/to-db-object { :name "Joe", :age 30 })]
|
doc (mgcnv/to-db-object { :name "Joe", :age 30 })]
|
||||||
(is (nil? (.get ^DBObject doc "_id")))
|
(is (nil? (.get ^DBObject doc "_id")))
|
||||||
(mgcol/insert "people" doc)
|
(mgcol/insert "people" doc)
|
||||||
(is (not (nil? (monger.util/get-id doc))))))
|
(is (not (nil? (monger.util/get-id doc))))))
|
||||||
|
|
@ -160,8 +162,8 @@
|
||||||
(mgcol/insert collection doc)
|
(mgcol/insert collection doc)
|
||||||
(def ^DBObject found-one (mgcol/find-one collection { :language "Clojure" }))
|
(def ^DBObject found-one (mgcol/find-one collection { :language "Clojure" }))
|
||||||
(is (= (:_id doc) (monger.util/get-id found-one)))
|
(is (= (:_id doc) (monger.util/get-id found-one)))
|
||||||
(is (= (monger.conversion/from-db-object found-one true) doc))
|
(is (= (mgcnv/from-db-object found-one true) doc))
|
||||||
(is (= (monger.conversion/to-db-object doc) found-one))))
|
(is (= (mgcnv/to-db-object doc) found-one))))
|
||||||
|
|
||||||
|
|
||||||
(deftest find-one-full-document-as-map-when-collection-has-matches
|
(deftest find-one-full-document-as-map-when-collection-has-matches
|
||||||
|
|
@ -289,7 +291,7 @@
|
||||||
{ :language "Clojure", :name "incanter" }
|
{ :language "Clojure", :name "incanter" }
|
||||||
{ :language "Scala", :name "akka" }])
|
{ :language "Scala", :name "akka" }])
|
||||||
(doseq [doc (take 3 (map (fn [dbo]
|
(doseq [doc (take 3 (map (fn [dbo]
|
||||||
(monger.conversion/from-db-object dbo true))
|
(mgcnv/from-db-object dbo true))
|
||||||
(mgcol/find-seq collection { :language "Clojure" })))]
|
(mgcol/find-seq collection { :language "Clojure" })))]
|
||||||
(is (= "Clojure" (:language doc))))))
|
(is (= "Clojure" (:language doc))))))
|
||||||
|
|
||||||
|
|
@ -326,7 +328,7 @@
|
||||||
(is (= 1 (.count scala-libs)))
|
(is (= 1 (.count scala-libs)))
|
||||||
(is (= 3 (.count clojure-libs)))
|
(is (= 3 (.count clojure-libs)))
|
||||||
(doseq [i clojure-libs]
|
(doseq [i clojure-libs]
|
||||||
(let [doc (monger.conversion/from-db-object i true)]
|
(let [doc (mgcnv/from-db-object i true)]
|
||||||
(is (= (:language doc) "Clojure"))))
|
(is (= (:language doc) "Clojure"))))
|
||||||
(is (empty? (mgcol/find collection { :language "Erlang" } [:name]))))))
|
(is (empty? (mgcol/find collection { :language "Erlang" } [:name]))))))
|
||||||
|
|
||||||
|
|
@ -408,7 +410,7 @@
|
||||||
|
|
||||||
(deftest save-a-new-basic-db-object
|
(deftest save-a-new-basic-db-object
|
||||||
(let [collection "people"
|
(let [collection "people"
|
||||||
doc (monger.conversion/to-db-object { :name "Joe", :age 30 })]
|
doc (mgcnv/to-db-object { :name "Joe", :age 30 })]
|
||||||
(is (nil? (monger.util/get-id doc)))
|
(is (nil? (monger.util/get-id doc)))
|
||||||
(mgcol/save "people" doc)
|
(mgcol/save "people" doc)
|
||||||
(is (not (nil? (monger.util/get-id doc))))))
|
(is (not (nil? (monger.util/get-id doc))))))
|
||||||
|
|
@ -495,3 +497,58 @@
|
||||||
(is (not (mgcol/exists? collection)))
|
(is (not (mgcol/exists? collection)))
|
||||||
(is (mgcol/exists? "gadgets"))
|
(is (mgcol/exists? "gadgets"))
|
||||||
(mgcol/drop "gadgets")))
|
(mgcol/drop "gadgets")))
|
||||||
|
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; Map/Reduce
|
||||||
|
;;
|
||||||
|
|
||||||
|
(let [collection "widgets"
|
||||||
|
mapper "function() {
|
||||||
|
emit(this.state, this.price * this.quantity)
|
||||||
|
}"
|
||||||
|
reducer "function(key, values) {
|
||||||
|
var result = 0;
|
||||||
|
values.forEach(function(v) { result += v });
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}"
|
||||||
|
batch [{ :state "CA" :quantity 1 :price 199.00 }
|
||||||
|
{ :state "NY" :quantity 2 :price 199.00 }
|
||||||
|
{ :state "NY" :quantity 1 :price 299.00 }
|
||||||
|
{ :state "IL" :quantity 2 :price 11.50 }
|
||||||
|
{ :state "CA" :quantity 2 :price 2.95 }
|
||||||
|
{ :state "IL" :quantity 3 :price 5.50 }]
|
||||||
|
expected [{:_id "CA", :value 204.9} {:_id "IL", :value 39.5} {:_id "NY", :value 697.0}]]
|
||||||
|
(deftest basic-inline-map-reduce-example
|
||||||
|
(mgcol/remove collection)
|
||||||
|
(is (mgres/ok? (mgcol/insert-batch collection batch)))
|
||||||
|
(let [output (mgcol/map-reduce collection mapper reducer nil MapReduceCommand$OutputType/INLINE {})
|
||||||
|
results (mgcnv/from-db-object ^DBObject (.results ^MapReduceOutput output) true)]
|
||||||
|
(mgres/ok? output)
|
||||||
|
(is (= expected results))))
|
||||||
|
|
||||||
|
(deftest basic-map-reduce-example-that-replaces-named-collection
|
||||||
|
(mgcol/remove collection)
|
||||||
|
(is (mgres/ok? (mgcol/insert-batch collection batch)))
|
||||||
|
(let [output (mgcol/map-reduce collection mapper reducer "mr_outputs" {})
|
||||||
|
results (mgcnv/from-db-object ^DBObject (.results ^MapReduceOutput output) true)]
|
||||||
|
(mgres/ok? output)
|
||||||
|
(is (= 3 (monger.core/count results)))
|
||||||
|
(is (= expected
|
||||||
|
(map #(mgcnv/from-db-object % true) (seq results))))
|
||||||
|
(is (= expected
|
||||||
|
(map #(mgcnv/from-db-object % true) (mgcol/find "mr_outputs"))))
|
||||||
|
(.drop ^MapReduceOutput output)))
|
||||||
|
|
||||||
|
(deftest basic-map-reduce-example-that-merged-results-into-named-collection
|
||||||
|
(mgcol/remove collection)
|
||||||
|
(is (mgres/ok? (mgcol/insert-batch collection batch)))
|
||||||
|
(mgcol/map-reduce collection mapper reducer "merged_mr_outputs" MapReduceCommand$OutputType/MERGE {})
|
||||||
|
(is (mgres/ok? (mgcol/insert collection { :state "OR" :price 17.95 :quantity 4 })))
|
||||||
|
(let [output (mgcol/map-reduce collection mapper reducer "merged_mr_outputs" MapReduceCommand$OutputType/MERGE {})]
|
||||||
|
(mgres/ok? output)
|
||||||
|
(is (= 4 (monger.core/count (.results ^MapReduceOutput output))))
|
||||||
|
(is (= ["CA" "IL" "NY" "OR"]
|
||||||
|
(map :_id (mgcol/find-maps "merged_mr_outputs"))))
|
||||||
|
(.drop ^MapReduceOutput output))))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue