About this guide

This guide covers:

  • Using MongoDB 2.2 Aggregation Framework with Clojure

This work is licensed under a Creative Commons Attribution 3.0 Unported License (including images & stylesheets). The source is available on Github.

What Version of Monger Does This Guide Cover?

This guide covers Monger 2.0 (including preview releases).

What Version of MongoDB Does This Guide Cover?

This guide covers a feature that was introduced with the release of MongoDB 2.2.

Overview

MongoDB 2.2 also supports a more focused, less generic and easier to use data processing feature called the Aggregation Framework which makes raw map/reduce a relatively low-level facility.

Performing MongoDB aggregation queries with Clojure

Conceptually, documents from a collection pass through an aggregation pipeline, which transforms these objects they pass through. For those familiar with UNIX-like shells (e.g. bash,) the concept is analogous to the pipe (i.e. |) used to string text filters together.

In a shell environment the pipe redirects a stream of characters from the output of one process to the input of the next. The MongoDB aggregation pipeline streams MongoDB documents from one pipeline operator to the next to process the documents.

All pipeline operators process a stream of documents and the pipeline behaves as if the operation scans a collection and passes all matching documents into the “top” of the pipeline. Each operator in the pipleine transforms each document as it passes through the pipeline.

monger.collection/aggregate is the function used to perform aggregation queries with Monger. It takes a collection name and a list of aggregation pipeline stages or pipeline operators, such as $project or $multiplyBy.

Pipeline operators are specified as documents (Clojure maps) and contain $operators similar to those used by perform queries and updates. They can be specified as strings, e.g. "$project", or using predefined operators from the monger.operators namespace, e.g. $project:

(ns monger.docs.examples
  (:require [monger.core :as mg]
            [monger.collection :as mc]
            [monger.operators :refer :all]))

;; performs an aggregation query.
;;
;; The following data set
;;
;; [{ :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   }]
;;
;; will be reduced to
;;
;; [{:_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}]
;;

(let [conn (mg/connect)
      db   (mg/get-db conn "monger-test")
      coll "docs"]
  (mc/aggregate db coll [{$project {:subtotal {$multiply ["$quantity", "$price"]}
                                                         :_id     "$state"}}])

  ;; alternative version, does not use predefined monger.operators/$project and monger.operators/$multiply operators
  (mc/aggregate db coll [{"$project" {:subtotal {"$multiply" ["$quantity", "$price"]}
                                                            :_id     "$state"}}]))

Unlike Map/Reduce operators, aggregation queries are always returned "inline" (as a value by monger.collection/aggregate).

For an in-depth overview of the MongoDB 2.2 Aggregation Framework, please refer to this MongoDB Aggregation Framework guide. There is also a pipeline operator reference.

The documentation is organized as a number of guides, covering all kinds of topics.

We recommend that you read the following guides first, if possible, in this order:

Tell Us What You Think!

Please take a moment to tell us what you think about this guide on Twitter or the Monger mailing list

Let us know what was unclear or what has not been covered. Maybe you do not like the guide style or grammar or discover spelling mistakes. Reader feedback is key to making the documentation better.

comments powered by Disqus