This guide covers:
Cheshire
and clojure.data.json
clj-time
and Joda Timeclojure.core.cache
: MongoDB-based Clojure cache protocol implementationThis work is licensed under a Creative Commons Attribution 3.0 Unported License (including images & stylesheets). The source is available on Github.
This guide covers Monger 3.1 (including preview releases).
Monger heavily relies on relatively recent Clojure features like protocols to integrate with libraries like Cheshire or clj-time (Joda Time). As the result you can focus on your application instead of figuring out how to glue two libraries together.
Many applications that use MongoDB and Monger have to serialize documents stored in the database to JSON and pass them to other applications using HTTP or messaging protocols such as AMQP 0.9.1 or ZeroMQ.
This means that MongoDB data types (object ids, documents) need to be serialized. While BSON, data format used by MongoDB, is semantically very similar to JSON, MongoDB drivers do not typically provide serialization to JSON and JSON serialization libraries typically do not support MongoDB data types.
Monger provides a convenient feature for Cheshire, a pretty popular modern JSON serialization library
for Clojure. The way it works is Monger will add custom serializes for MongoDB Java
driver data types: org.bson.types.ObjectId
and com.mongodb.DBObject
if you opt-in for it.
To use it, you need to add Chshire dependency to your project, for example (with Leiningen)
[cheshire "5.3.1"]
and then require monger.json
namespace like so:
(ns mycompany.myservice
(:require monger.json))
when loaded, code in that namespace will extend necessary protocols
and that's it. Then you can pass documents that contain object ids in
them to JSON serialization functions from cheshire.custom
and
everything will just work.
This feature is optional: Monger does not depend on Cheshire
or
clojure.data.json
and won't add unused dependencies to your project.
Monger only works clojure.data.json
0.2.x
and 0.1.x
. Support for versions
earlier than 0.2.x
will be dropped in one of the future releases.
Because of various shortcomings of Java date/time classes provided by the JDK, many projects choose to use Joda Time to work with dates.
To be able to insert documents with Joda Time date values in them, you
need to require monger.joda-time
namespace:
(ns mycompany.myservice
(:require monger.joda-time))
Just like with clojure.data.json
integration, there is nothing else
you have to do. This feature is optional: Monger does not depend on
clj-time
or Joda Time
and won't add unused dependencies to your
project.
When Joda Time integration is loaded, Monger extends its own Clojure-to-DBObject conversion protocol to support Joda Time date/time/instant types
and convert loaded dates to Joda Time dates. When a new Joda Time org.joda.time.DateTime
instance is created, it will use an environment-specific
time zone by default (configured via the user.timezone
JVM property). Because altering user.timezone
may also affect other libraries,
it is recommended to set default time zone using Joda Time API like so:
(import org.joda.time.DateTimeZone)
;; set default time zone that a org.joda.time.DateTime instances
;; will use
(DateTimeZone/setDefault DateTimeZone/UTC)
This will only have effect on Joda Time (and, in turn, Monger date/time/instant deserialization).
monger.joda-time
and monger.json
only extend existing protocols
and do not define public functions. Due to a subtle bug in Clojure
1.5, using the ns
macro's :use
option on such namespace will fail. But worry not:
there is no need to use :use
. Just use :require
, it will cause
protocol extensions to be compiled and that's all you need to use
Monger's integration points.
Monger provides a MongoDB-backed cache implementation that conforms to
the clojure.core.cache
protocol. It uses the cache_entries
for
caches by default. You can use any number of cache data structure
instances as your application may need.
To use Monger's cache implementation, use functions in both
clojure.core.cache
and monger.cache
namespaces, then create a
cache store using monger.cache/basic-monger-cache-factory
that can
be passed a collection name you want the cache to use:
(ns monger.docs.examples
(:require [monger.core :as mg]
[clojure.core.cache :refer :all]
[monger.cache :refer :all]))
(defn generate-uuid
[]
(str (java.util.UUID/randomUUID)))
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")
store (basic-monger-cache-factory db "cached_items")]
;; now use the store
(has? store (genenrate-uuid)) ;= false
(lookup store "another-key")
(evict store "third-key")
;; puts a new value in the cache
(miss store "fourth-key" {:name "Joe" :score 10288}))
Then use the store like you would any other core.cache
store, database backed or not.
It is common to use capped or TTL collections for caches. Pass
monger.cache/basic-monger-cache-factory
a database and collection name, and the
cache instance will use it:
(ns monger.docs.examples
(:require [monger.core :as mg]
[clojure.core.cache :refer :all]
[monger.cache :refer :all]))
(defn generate-uuid
[]
(str (java.util.UUID/randomUUID)))
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")
store (basic-monger-cache-factory db "myapp.caches")]
(comment "The store will now use the myapp.caches collection"))
To learn more about the clojure.core.cache protocol and functions it provides, see clojure.core.cache documentation.
Monger provides a MongoDB-backed session store for Ring,
Clojure's ubiquitous HTTP middleware
library. It can be found in the
monger.ring.session-store
namespace. To create a new store, use the
monger.ring.session-store/monger-store
that takes a database and name of the
collection sessions will be stored in:
(ns monger.docs.examples
(:require [monger.core :as mg]
[monger.ring.session-store :refer [monger-store]]))
;; create a new store, typically passed to server handlers
;; with libraries like Compojure
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(monger-store db "sessions"))
Monger provides an alternative MongoDB-backed Ring session store that
uses Clojure reader serialization. This means this store stores data
in a way that non-Clojure applications won't be able to read easily
but also supports edge cases in Clojure data type serialization that
Monger itself does not, for example, namespaced keywords (like
::identity
).
This is the Ring session store you should use if you want to use Monger with Friend, a popular authentication and authorization library for Clojure.
It works exactly the same way but the name of the function that creates a store is different:
(ns monger.docs.examples
(:require [monger.core :as mg]
[monger.ring.session-store :refer [session-store]]))
(let [conn (mg/connect)
db (mg/get-db conn "monger-test")]
(session-store db "sessions"))
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:
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.