MQL support

MQL and cMQL can be mixed freely
But cMQL wraps all aggregation stages/operators so generally there is no need

For example i can have a MQL stage,that uses also a cMQL operator

(q :testdb.testcoll
{"$and" [(=_ :gender "male") {"$eq" ["$type" "student"]}]}}}
[:!_id :maleStudent]
(skip 2)
(limit 1))

The bellow notation is to make MQL easier they dont restrict MQL


Keyword on the left of a map is just a string

{:aField avalue} = {"aField" avalue}

Field references

Keyword everywhere else is a reference (references cant be keys so there is no conflict)

:afield = "$afield"


:avar. = "$$avar"
:avar.field1. = "$$avar.field1"

System variables

:ROOT. = "$$ROOT"


{:afield (reduce (fn [:sum. :n.] (+ :sum. :n.))

*keywords are auto-completed in IDE's for example cursive helps on that

Filter ()

(< :age 25)
(= :gender "female")

Filters one after another become 1 $match stage,with $and and $expr added.
Don't use as filters things like bellow see [Query operators and Update operators]

{:gender "female"}

Project []

[:a :!_id {:c ''} {:!d ''} ...]
:a = keep a
:!_id = unset _id
{:c ...} = add :c
{:!d ...} = replace :d
*(its always replace by default except add document to array place)

AddFields {}

{:a1 (inc :a) :!a2 {} ...}
add :a1
replace :a2
*(its always replace by default except add document to array place,
or document to document place(causes merge))

*In the rare case where we want to add a field that has the name of a command option

(add {:allowDiskUse "myvalue"}) ;; solves the rare problem


  1. nil/empty stages are removed This allows to have conditional stages
  2. nested stages(even if many levels) becomes flatten
    This allows functions to generate 2 or more stages that added to the pipeline


(def x? false)
(defn f [] [stage2 stage3])
(q :testdb.testcoll
(if x? stage1)
Pipeline will become [stage2 stage3] (nil removed,stages flatten)
It will run as if it was
(q :testdb.testcoll

Aggregation framework

cMQL approach is

  1. use aggregation
  2. implement the operator with other aggregation operators
  3. use raw MQL inside cMQL (for example the bellow match)
  4. use javascript
  5. use the driver methods
  6. use MQL commands

cMQL commands uses aggregation operators for query and for pipelines for updates. To use cMQL MongoDB >= 4.2 is needed and to use the javascript in aggregation MongoDB >= 4.4 is needed

The reason is to be easy and program in 1 way
Aggregation framework can do almost all that query or update operators can do and much more
If something is needed it can be added in the future

Query and Update operators

cMQL uses aggregation by default

  1. Query operators can be used but in raw MQL

    (match { "price" { "$ne" 1.99 "$exists" true }})

    cMQL supports the find command but it makes it look like pipeline also For example the above would be (internaly is a find , not aggregation)

    (not= :price 1.99)
    (exists? :price))
  2. Update operators are not wrapped from cMQL
    Driver methods can be used or MQL update commands

    cMQL pipepline updates has operators like get-in and assoc-in that allows complex updates to be easily done

    (assoc-in :channel
    [{:cond (=_ "switch") :kcond (= :k "formats")} ;;key by condition
    {:icond (=_ :v.formatName. "ISO8583-93")} ;;index by condition
    5 ;;array index
    "alias"] ;;document key


cMQL commands are similar to MQL but not completly the same The reason is to provide less verbose and intuitive commands

Command options

Commands options can be given as

Single maps
{:allowDiskUse true}
{"allowDiskUse" true} (always cMQL convers the key to string)
Many pairs map
{:allowDiskUse true
:option2 false}
With operator(if option function exists in cMQL)
(allow-disk-use) => {"allowDiskUse" true}

More Info

For more info see documentation,the API and the docstrings