MongoDB 2.1 Aggregation Framework support
This commit is contained in:
parent
7d595874aa
commit
63f7099350
4 changed files with 155 additions and 7 deletions
61
ChangeLog.md
61
ChangeLog.md
|
|
@ -1,5 +1,66 @@
|
|||
## Changes between 1.0.0-beta7 and 1.0.0-beta8
|
||||
|
||||
### MongoDB 2.1/2.2 Aggregation Framework support
|
||||
|
||||
`monger.collection/aggregate` provides a convenient way to run [aggregation queries](http://docs.mongodb.org/manual/reference/aggregation/).
|
||||
|
||||
``` clojure
|
||||
;; single stage pipeline
|
||||
(mc/aggregate "docs" [{$project {:subtotal {$multiply ["$quantity", "$price"]}
|
||||
:_id "$state"}}])
|
||||
|
||||
;; two stage pipeline
|
||||
(mc/aggregate "docs" [{$project {:subtotal {$multiply ["$quantity", "$price"]}
|
||||
:_id 1
|
||||
:state 1}}
|
||||
{$group {:_id "$state"
|
||||
:total {$sum "$subtotal"}}}])
|
||||
```
|
||||
|
||||
The following couple of tests demonstrates aggregation queries with some sample data:
|
||||
|
||||
``` clojure
|
||||
(deftest ^{:edge-features true} test-basic-projection-with-multiplication
|
||||
(let [collection "docs"
|
||||
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 "NY" :subtotal 398.0}
|
||||
{:_id "NY" :subtotal 299.0}
|
||||
{:_id "IL" :subtotal 23.0}
|
||||
{:_id "CA" :subtotal 5.9}
|
||||
{:_id "IL" :subtotal 16.5}
|
||||
{:_id "CA" :subtotal 199.0}]]
|
||||
(mc/insert-batch collection batch)
|
||||
(let [result (vec (mc/aggregate "docs" [{$project {:subtotal {$multiply ["$quantity", "$price"]}
|
||||
:_id "$state"}}]))]
|
||||
(is (= expected result)))))
|
||||
|
||||
|
||||
(deftest ^{:edge-features true} test-basic-total-aggregation
|
||||
(let [collection "docs"
|
||||
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", :total 204.9} {:_id "IL", :total 39.5} {:_id "NY", :total 697.0}]]
|
||||
(mc/insert-batch collection batch)
|
||||
(let [result (vec (mc/aggregate "docs" [{$project {:subtotal {$multiply ["$quantity", "$price"]}
|
||||
:_id 1
|
||||
:state 1}}
|
||||
{$group {:_id "$state"
|
||||
:total {$sum "$subtotal"}}}]))]
|
||||
(is (= expected result)))))
|
||||
```
|
||||
|
||||
The aggregation framework is an edge feature that will be available in MongoDB 2.2.
|
||||
|
||||
|
||||
### More Operators
|
||||
|
||||
Two new operator macros: `$regex`, `$options` and those used by the upcoming
|
||||
|
|
|
|||
18
project.clj
18
project.clj
|
|
@ -6,13 +6,17 @@
|
|||
[org.mongodb/mongo-java-driver "2.7.3"]
|
||||
[com.novemberain/validateur "1.1.0"]
|
||||
[clojurewerkz/support "0.4.0"]]
|
||||
:test-selectors {:default (complement :performance)
|
||||
:focus :focus
|
||||
:indexing :indexing
|
||||
:external :external
|
||||
:cache :cache
|
||||
:performance :performance
|
||||
:all (constantly true)}
|
||||
:test-selectors {:default (fn [m]
|
||||
(and (not (:performance m))
|
||||
(not (:edge-features m))))
|
||||
:focus :focus
|
||||
:indexing :indexing
|
||||
:external :external
|
||||
:cache :cache
|
||||
:performance :performance
|
||||
;; as in, edge mongodb server
|
||||
:edge-features :edge-features
|
||||
:all (constantly true)}
|
||||
:codox {:exclude [monger.internal.pagination]}
|
||||
:mailing-list {:name "clojure-monger"
|
||||
:archive "https://groups.google.com/group/clojure-monger"
|
||||
|
|
|
|||
|
|
@ -596,3 +596,17 @@
|
|||
and :size (max allowed size of the collection, in bytes)."
|
||||
[^String name options]
|
||||
(.createCollection ^DB monger.core/*mongodb-database* name (to-db-object options)))
|
||||
|
||||
;;
|
||||
;; Aggregation
|
||||
;;
|
||||
|
||||
(defn aggregate
|
||||
"Performs aggregation query. MongoDB 2.1/2.2+ only.
|
||||
|
||||
See http://docs.mongodb.org/manual/applications/aggregation/ to learn more."
|
||||
[^String coll stages]
|
||||
(let [res (monger.core/command {:aggregate coll :pipeline stages})]
|
||||
;; this is what DBCollection#distinct does. Turning a blind eye!
|
||||
(.throwOnError res)
|
||||
(map #(from-db-object % true) (.get res "result"))))
|
||||
|
|
|
|||
69
test/monger/test/aggregation_framework_test.clj
Normal file
69
test/monger/test/aggregation_framework_test.clj
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
(ns monger.test.aggregation-framework-test
|
||||
(:require monger.core [monger.collection :as mc]
|
||||
[monger.test.helper :as helper])
|
||||
(:use clojure.test
|
||||
monger.operators
|
||||
monger.test.fixtures))
|
||||
|
||||
|
||||
(helper/connect!)
|
||||
|
||||
(use-fixtures :each purge-docs)
|
||||
|
||||
(deftest ^{:edge-features true} test-basic-single-stage-$project-aggregation
|
||||
(let [collection "docs"
|
||||
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 [{:quantity 1 :state "CA"}
|
||||
{:quantity 2 :state "NY"}
|
||||
{:quantity 1 :state "NY"}
|
||||
{:quantity 2 :state "IL"}
|
||||
{:quantity 2 :state "CA"}
|
||||
{:quantity 3 :state "IL"}]]
|
||||
(mc/insert-batch collection batch)
|
||||
(is (= 6 (mc/count collection)))
|
||||
(let [result (vec (map #(select-keys % [:state :quantity])
|
||||
(mc/aggregate "docs" [{$project {:state 1 :quantity 1}}])))]
|
||||
(is (= expected result)))))
|
||||
|
||||
|
||||
(deftest ^{:edge-features true} test-basic-projection-with-multiplication
|
||||
(let [collection "docs"
|
||||
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 "NY" :subtotal 398.0}
|
||||
{:_id "NY" :subtotal 299.0}
|
||||
{:_id "IL" :subtotal 23.0}
|
||||
{:_id "CA" :subtotal 5.9}
|
||||
{:_id "IL" :subtotal 16.5}
|
||||
{:_id "CA" :subtotal 199.0}]]
|
||||
(mc/insert-batch collection batch)
|
||||
(let [result (vec (mc/aggregate "docs" [{$project {:subtotal {$multiply ["$quantity", "$price"]}
|
||||
:_id "$state"}}]))]
|
||||
(is (= expected result)))))
|
||||
|
||||
|
||||
(deftest ^{:edge-features true} test-basic-total-aggregation
|
||||
(let [collection "docs"
|
||||
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", :total 204.9} {:_id "IL", :total 39.5} {:_id "NY", :total 697.0}]]
|
||||
(mc/insert-batch collection batch)
|
||||
(let [result (vec (mc/aggregate "docs" [{$project {:subtotal {$multiply ["$quantity", "$price"]}
|
||||
:_id 1
|
||||
:state 1}}
|
||||
{$group {:_id "$state"
|
||||
:total {$sum "$subtotal"}}}]))]
|
||||
(is (= expected result)))))
|
||||
Loading…
Reference in a new issue