515 lines
18 KiB
Clojure
515 lines
18 KiB
Clojure
;; Copyright (c) 2011 Michael S. Klishin
|
|
;;
|
|
;; The use and distribution terms for this software are covered by the
|
|
;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
|
|
;; which can be found in the file epl-v10.html at the root of this distribution.
|
|
;; By using this software in any fashion, you are agreeing to be bound by
|
|
;; the terms of this license.
|
|
;; You must not remove this notice, or any other, from this software.
|
|
|
|
(ns monger.collection
|
|
(:refer-clojure :exclude [find remove count drop distinct empty?])
|
|
(: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])
|
|
(:use [monger.conversion]))
|
|
|
|
;;
|
|
;; API
|
|
;;
|
|
|
|
;;
|
|
;; monger.collection/insert
|
|
;;
|
|
|
|
(defn ^WriteResult insert
|
|
"Saves @document@ to @collection@. You can optionally specify WriteConcern.
|
|
|
|
EXAMPLES:
|
|
|
|
(monger.collection/insert \"people\" { :name \"Joe\", :age 30 })
|
|
|
|
(monger.collection/insert \"people\" { :name \"Joe\", :age 30, WriteConcern/SAFE })
|
|
"
|
|
([^String collection ^DBObject document]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.insert ^DBCollection coll ^DBObject (to-db-object document) ^WriteConcern monger.core/*mongodb-write-concern*)))
|
|
([^String collection ^DBObject document ^WriteConcern concern]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.insert ^DBCollection coll ^DBObject (to-db-object document) ^WriteConcern concern)))
|
|
([^DB db ^String collection ^DBObject document ^WriteConcern concern]
|
|
(let [^DBCollection coll (.getCollection db collection)]
|
|
(.insert ^DBCollection coll ^DBObject (to-db-object document) ^WriteConcern concern))))
|
|
|
|
|
|
(defn ^WriteResult insert-batch
|
|
"Saves @documents@ do @collection@. You can optionally specify WriteConcern as a third argument.
|
|
|
|
EXAMPLES:
|
|
|
|
(monger.collection/insert-batch \"people\" [{ :name \"Joe\", :age 30 }, { :name \"Paul\", :age 27 }])
|
|
|
|
(monger.collection/insert-batch \"people\" [{ :name \"Joe\", :age 30 }, { :name \"Paul\", :age 27 }] WriteConcern/NORMAL)
|
|
|
|
"
|
|
([^String collection, ^List documents]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.insert ^DBCollection coll ^List (to-db-object documents) ^WriteConcern monger.core/*mongodb-write-concern*)))
|
|
([^String collection, ^List documents, ^WriteConcern concern]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.insert ^DBCollection coll ^List (to-db-object documents) ^WriteConcern concern)))
|
|
([^DB db ^String collection, ^List documents, ^WriteConcern concern]
|
|
(let [^DBCollection coll (.getCollection db collection)]
|
|
(.insert ^DBCollection coll ^List (to-db-object documents) ^WriteConcern concern))))
|
|
|
|
;;
|
|
;; monger.collection/find
|
|
;;
|
|
(declare fields-to-db-object)
|
|
|
|
(defn ^DBCursor find
|
|
"Queries for objects in this collection.
|
|
This function returns DBCursor, which allows you to iterate over DBObjects.
|
|
If you want to manipulate clojure sequences maps, please @find-maps@.
|
|
|
|
EXAMPLES:
|
|
;; return all objects in this collection.
|
|
(mgcol/find \"people\")
|
|
|
|
;; return all objects matching query
|
|
(mgcol/find \"people\" { :company \"Comp Corp\"})
|
|
|
|
;; return all objects matching query, taking only specified fields
|
|
(mgcol/find \"people\" { :company \"Comp Corp\"} [:first_name :last_name])
|
|
"
|
|
([^String collection]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.find coll)))
|
|
([^String collection ^Map ref]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.find ^DBCollection coll ^DBObject (to-db-object ref))))
|
|
([^String collection ^Map ref ^List fields]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)
|
|
map-of-fields (fields-to-db-object fields)]
|
|
(.find ^DBCollection coll ^DBObject (to-db-object ref) ^DBObject (to-db-object map-of-fields))))
|
|
([^DB db ^String collection ^Map ref ^List fields]
|
|
(let [^DBCollection coll (.getCollection db collection)
|
|
map-of-fields (fields-to-db-object fields)]
|
|
(.find ^DBCollection coll ^DBObject (to-db-object ref) ^DBObject (to-db-object map-of-fields)))))
|
|
|
|
(defn ^ISeq find-maps
|
|
"Queries for objects in this collection.
|
|
This function returns clojure Seq of Maps.
|
|
If you want to work directly with DBObject, use find.
|
|
"
|
|
([^String collection]
|
|
(map (fn [x] (from-db-object x true)) (find collection)))
|
|
([^String collection ^Map ref]
|
|
(map (fn [x] (from-db-object x true)) (find collection ref)))
|
|
([^String collection ^Map ref ^List fields]
|
|
(map (fn [x] (from-db-object x true)) (find collection ref fields)))
|
|
([^DB db ^String collection ^Map ref ^List fields]
|
|
(map (fn [x] (from-db-object x true)) (find db collection ref fields))))
|
|
|
|
(defn ^ISeq find-seq
|
|
"Queries for objects in this collection, returns ISeq of DBObjects."
|
|
([^String collection]
|
|
(seq (find collection)))
|
|
([^String collection ^Map ref]
|
|
(seq (find collection ref)))
|
|
([^String collection ^Map ref ^List fields]
|
|
(seq (find collection ref fields)))
|
|
([^DB db ^String collection ^Map ref ^List fields]
|
|
(seq (find db collection ref fields))))
|
|
|
|
;;
|
|
;; monger.collection/find-one
|
|
;;
|
|
|
|
(defn ^DBObject find-one
|
|
"Returns a single DBObject from this collection matching the query.
|
|
|
|
EXAMPLES:
|
|
|
|
(mgcol/find-one collection { :language \"Clojure\" })
|
|
|
|
;; Return only :language field.
|
|
;; Note that _id field is always returned.
|
|
(mgcol/find-one collection { :language \"Clojure\" } [:language])
|
|
|
|
"
|
|
([^String collection ^Map ref]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.findOne ^DBCollection coll ^DBObject (to-db-object ref))))
|
|
([^String collection ^Map ref ^List fields]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)
|
|
map-of-fields (fields-to-db-object fields)]
|
|
(.findOne ^DBCollection coll ^DBObject (to-db-object ref) ^DBObject (to-db-object map-of-fields))))
|
|
([^DB db ^String collection ^Map ref ^List fields]
|
|
(let [^DBCollection coll (.getCollection db collection)
|
|
map-of-fields (fields-to-db-object fields)]
|
|
(.findOne ^DBCollection coll ^DBObject (to-db-object ref) ^DBObject (to-db-object map-of-fields)))))
|
|
|
|
(defn ^IPersistentMap find-one-as-map
|
|
"Returns a single object converted to Map from this collection matching the query."
|
|
([^String collection ^Map ref]
|
|
(from-db-object ^DBObject (find-one collection ref) true))
|
|
([^String collection ^Map ref keywordize]
|
|
(from-db-object ^DBObject (find-one collection ref) keywordize))
|
|
([^String collection ^Map ref ^List fields keywordize]
|
|
(from-db-object ^DBObject (find-one collection ref fields) keywordize)))
|
|
|
|
|
|
|
|
;;
|
|
;; monger.collection/find-by-id
|
|
;;
|
|
|
|
(defn ^DBObject find-by-id
|
|
"Returns a single object with matching _id field.
|
|
|
|
EXAMPLES:
|
|
|
|
(mgcol/find-one-by-id collection \"4ef45ab4744e9fd632640e2d\")
|
|
|
|
;; Return only :language field.
|
|
;; Note that _id field is always returned.
|
|
(mgcol/find-one-by-id collection \"4ef45ab4744e9fd632640e2d\" [:language])
|
|
"
|
|
([^String collection id]
|
|
(find-one collection { :_id id }))
|
|
([^String collection id ^List fields]
|
|
(find-one collection { :_id id } fields))
|
|
([^DB db ^String collection id ^List fields]
|
|
(find-one db collection { :_id id } fields)))
|
|
|
|
(defn ^IPersistentMap find-map-by-id
|
|
"Returns a single object, converted to map with matching _id field."
|
|
([^String collection id]
|
|
(from-db-object ^DBObject (find-one-as-map collection { :_id id }) true))
|
|
([^String collection id keywordize]
|
|
(from-db-object ^DBObject (find-one-as-map collection { :_id id }) keywordize))
|
|
([^String collection id ^List fields keywordize]
|
|
(from-db-object ^DBObject (find-one-as-map collection { :_id id } fields) keywordize)))
|
|
|
|
|
|
;;
|
|
;; monger.collection/group
|
|
;;
|
|
|
|
|
|
;; TBD
|
|
|
|
|
|
;;
|
|
;; monger.collection/count
|
|
;;
|
|
(defn count
|
|
"Returns the number of documents in this collection.
|
|
|
|
Takes optional conditions as an argument.
|
|
|
|
(monger.collection/count collection)
|
|
|
|
(monger.collection/count collection { :first_name \"Paul\" })"
|
|
(^long [^String collection]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.count coll)))
|
|
(^long [^String collection ^Map conditions]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.count coll (to-db-object conditions))))
|
|
(^long [^DB db ^String collection ^Map conditions]
|
|
(let [^DBCollection coll (.getCollection db collection)]
|
|
(.count coll (to-db-object conditions)))))
|
|
|
|
(defn any?
|
|
"Wether the collection has any items at all, or items matching query.
|
|
|
|
EXAMPLES:
|
|
|
|
;; wether the collection has any items
|
|
(mgcol/any? collection)
|
|
|
|
(mgcol/any? collection { :language \"Clojure\" }))
|
|
"
|
|
([^String collection]
|
|
(> (count collection) 0))
|
|
([^String collection ^Map conditions]
|
|
(> (count collection conditions) 0))
|
|
([^DB db ^String collection ^Map conditions]
|
|
(> (count db collection conditions) 0)))
|
|
|
|
|
|
(defn empty?
|
|
"Wether the collection is empty.
|
|
|
|
EXAMPLES:
|
|
(mgcol/empty? \"things\")
|
|
"
|
|
([^String collection]
|
|
(= (count collection) 0))
|
|
([^DB db ^String collection]
|
|
(= (count db collection {}) 0)))
|
|
|
|
;; monger.collection/update
|
|
|
|
(defn ^WriteResult update
|
|
"Performs an update operation.
|
|
|
|
Please note that update is potentially destructive operation. It will update your document with the given set
|
|
emptying the fields not mentioned in (^Map document). In order to only change certain fields, please use
|
|
\"$set\".
|
|
|
|
EXAMPLES
|
|
|
|
(monger.collection/update \"people\" { :first_name \"Raul\" } { \"$set\" { :first_name \"Paul\" } })
|
|
|
|
You can use all the Mongodb Modifier Operations ($inc, $set, $unset, $push, $pushAll, $addToSet, $pop, $pull
|
|
$pullAll, $rename, $bit) here, as well
|
|
|
|
EXAMPLES
|
|
|
|
(monger.collection/update \"people\" { :first_name \"Paul\" } { \"$set\" { :index 1 } })
|
|
(monger.collection/update \"people\" { :first_name \"Paul\" } { \"$inc\" { :index 5 } })
|
|
|
|
(monger.collection/update \"people\" { :first_name \"Paul\" } { \"$unset\" { :years_on_stage 1} })
|
|
|
|
It also takes modifiers, such as :upsert and :multi.
|
|
|
|
EXAMPLES
|
|
|
|
;; add :band field to all the records found in \"people\" collection, otherwise only the first matched record
|
|
;; will be updated
|
|
(monger.collection/update \"people\" { } { \"$set\" { :band \"The Beatles\" }} :multi true)
|
|
|
|
;; inserts the record if it did not exist in the collection
|
|
(monger.collection/update \"people\" { :first_name \"Yoko\" } { :first_name \"Yoko\" :last_name \"Ono\" } :upsert true)
|
|
|
|
By default :upsert and :multi are false."
|
|
[^String collection ^Map conditions ^Map document & { :keys [upsert multi write-concern] :or { upsert false, multi false, write-concern monger.core/*mongodb-write-concern* } }]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.update coll (to-db-object conditions) (to-db-object document) upsert multi write-concern)))
|
|
|
|
|
|
;; monger.collection/save
|
|
|
|
(defn ^WriteResult save
|
|
"Saves an object to the given collection (does insert or update based on the object _id).
|
|
|
|
If the object is not present in the database, insert operation will be performed.
|
|
If the object is already in the database, it will be updated.
|
|
|
|
EXAMPLES
|
|
|
|
(monger.collection/save \"people\" { :first_name \"Ian\" :last_name \"Gillan\" })
|
|
"
|
|
([^String collection ^Map document]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.save coll (to-db-object document) monger.core/*mongodb-write-concern*)))
|
|
([^String collection ^Map document ^WriteConcern write-concern]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.save coll document write-concern)))
|
|
([^DB db ^String collection ^Map document ^WriteConcern write-concern]
|
|
(let [^DBCollection coll (.getCollection db collection)]
|
|
(.save coll document write-concern))))
|
|
|
|
|
|
;; monger.collection/remove
|
|
|
|
(defn ^WriteResult remove
|
|
"Removes objects from the database.
|
|
|
|
EXAMPLES
|
|
|
|
(monger.collection/remove collection) ;; Removes all documents from DB
|
|
|
|
(monger.collection/remove collection { :language \"Clojure\" }) ;; Removes documents based on given query
|
|
|
|
"
|
|
([^String collection]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.remove coll (to-db-object {}))))
|
|
([^String collection ^Map conditions]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.remove coll (to-db-object conditions))))
|
|
([^DB db ^String collection ^Map conditions]
|
|
(let [^DBCollection coll (.getCollection db collection)]
|
|
(.remove coll (to-db-object conditions)))))
|
|
|
|
|
|
|
|
;;
|
|
;; monger.collection/create-index
|
|
;;
|
|
|
|
(defn create-index
|
|
"Forces creation of index on a set of fields, if one does not already exists.
|
|
|
|
EXAMPLES
|
|
|
|
;; Will create an index on \"language\" field
|
|
(monger.collection/create-index collection { \"language\" 1 })
|
|
|
|
"
|
|
([^String collection ^Map keys]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.createIndex coll (to-db-object keys))))
|
|
([^DB db ^String collection ^Map keys]
|
|
(let [^DBCollection coll (.getCollection db collection)]
|
|
(.createIndex coll (to-db-object keys)))))
|
|
|
|
|
|
;;
|
|
;; monger.collection/ensure-index
|
|
;;
|
|
|
|
(defn ensure-index
|
|
"Creates an index on a set of fields, if one does not already exist.
|
|
ensureIndex in Java driver is optimized and is inexpensive if the index already exists.
|
|
|
|
EXAMPLES
|
|
|
|
(monger.collection/ensure-index collection { \"language\" 1 })
|
|
|
|
"
|
|
([^String collection, ^Map keys]
|
|
(let [coll ^DBCollection (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.ensureIndex ^DBCollection coll ^DBObject (to-db-object keys))))
|
|
([^String collection, ^Map keys, ^String name]
|
|
(let [coll ^DBCollection (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.ensureIndex coll ^DBObject (to-db-object keys) ^String name))))
|
|
|
|
|
|
;;
|
|
;; monger.collection/indexes-on
|
|
;;
|
|
|
|
(defn indexes-on
|
|
"Return a list of the indexes for this collection.
|
|
|
|
EXAMPLES
|
|
|
|
(monger.collection/indexes-on collection)
|
|
|
|
"
|
|
[^String collection]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(from-db-object (.getIndexInfo coll) true)))
|
|
|
|
|
|
;;
|
|
;; monger.collection/drop-index
|
|
;;
|
|
|
|
(defn drop-index
|
|
"Drops an index from this collection."
|
|
([^String collection ^String name]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.dropIndex coll name)))
|
|
([^DB db ^String collection ^String name]
|
|
(let [^DBCollection coll (.getCollection db collection)]
|
|
(.dropIndex coll name))))
|
|
|
|
(defn drop-indexes
|
|
"Drops an indices from this collection."
|
|
([^String collection]
|
|
(.dropIndexes ^DBCollection (.getCollection monger.core/*mongodb-database* collection)))
|
|
([^DB db ^String collection]
|
|
(.dropIndexes ^DBCollection (.getCollection db collection))))
|
|
|
|
|
|
;;
|
|
;; monger.collection/exists?, /create, /drop, /rename
|
|
;;
|
|
|
|
|
|
(defn exists?
|
|
"Checks weather collection with certain name exists.
|
|
|
|
EXAMPLE:
|
|
|
|
(monger.collection/exists? \"coll\")
|
|
"
|
|
([^String collection]
|
|
(.collectionExists monger.core/*mongodb-database* collection))
|
|
([^DB db ^String collection]
|
|
(.collectionExists db collection)))
|
|
|
|
(defn create
|
|
"Creates a collection with a given name and options."
|
|
([^String collection ^Map options]
|
|
(.createCollection monger.core/*mongodb-database* collection (to-db-object options)))
|
|
([^DB db ^String collection ^Map options]
|
|
(.createCollection db collection (to-db-object options))))
|
|
|
|
(defn drop
|
|
"Deletes collection from database.
|
|
|
|
EXAMPLE:
|
|
|
|
(monger.collection/drop \"collection-to-drop\")
|
|
"
|
|
([^String collection]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.drop coll)))
|
|
([^DB db ^String collection]
|
|
(let [^DBCollection coll (.getCollection db collection)]
|
|
(.drop coll))))
|
|
|
|
(defn rename
|
|
"Renames collection.
|
|
|
|
EXAMPLE:
|
|
|
|
(monger.collection/rename \"old_name\" \"new_name\")
|
|
"
|
|
([^String from, ^String to]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* from)]
|
|
(.rename coll to)))
|
|
([^String from ^String to ^Boolean drop-target]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* from)]
|
|
(.rename coll to drop-target)))
|
|
([^DB db ^String from ^String to ^Boolean drop-target]
|
|
(let [^DBCollection coll (.getCollection db from)]
|
|
(.rename coll to drop-target))))
|
|
|
|
;;
|
|
;; Map/Reduce
|
|
;;
|
|
|
|
(defn map-reduce
|
|
"Performs a map reduce operation"
|
|
([^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)))))
|
|
|
|
|
|
;;
|
|
;; monger.collection/distinct
|
|
;;
|
|
|
|
(defn distinct
|
|
"Finds distinct values for a key"
|
|
([^String collection ^String key]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.distinct coll ^String (to-db-object key))))
|
|
([^String collection ^String key ^Map query]
|
|
(let [^DBCollection coll (.getCollection monger.core/*mongodb-database* collection)]
|
|
(.distinct coll ^String (to-db-object key) ^DBObject (to-db-object query))))
|
|
([^DB db ^String collection ^String key ^Map query]
|
|
(let [^DBCollection coll (.getCollection db collection)]
|
|
(.distinct coll ^String (to-db-object key) ^DBObject (to-db-object query)))))
|
|
|
|
|
|
|
|
;;
|
|
;; Implementation
|
|
;;
|
|
|
|
(defn- fields-to-db-object
|
|
[^List fields]
|
|
(zipmap fields (repeat 1)))
|