Skip to content

Query Syntax

monq’s simple query mode lets you filter and project in a single query string — no separator needed. Open it with /.

A word with no field: searches every string field, and the results update as you type.

alice → "alice" in any string field (case-insensitive)
alice berlin → both words, possibly in different fields
"new york" → one phrase
alice status:active → search AND status=active
alice !berlin → "alice" somewhere, "berlin" nowhere

Each term becomes a case-insensitive substring $regex over every string field and array of strings in the sampled schema, nested paths included (up to 40 fields), OR-ed together. Several terms AND together.

A term that parses as a value also matches fields of that type:

Term Also matches
24 hex characters objectid fields, including _id, by equality
A number (42, -3.5) number fields by equality
YYYY-MM-DD date fields within that UTC day
Detail Behaviour
Live Re-queries 300 ms after the terms change, once every term has 2+ characters. Enter still submits and records history
Special characters A term containing :, <, >, = or ! must be quoted: "a:b". Regex characters are matched literally
Fields Only fields the schema sample has seen. With none, the search matches nothing
Cost Regex search can’t use an index; it scans the collection and times out after 10 s

Prefix a term with ! to hide documents that contain it: !stefan, !"new york". The term becomes { $nor: [ … ] } over the same fields a positive term searches, type-aware matches included, and ANDs with everything else. A document without any of those fields is kept. The prefix is ! rather than - because a bare -word excludes the field word from the projection.

Excluded terms aren’t highlighted, and the filter bar counts them: ⌕ regex · 12 fields · 1 excluded.

Matches are highlighted in the document list. The filter bar shows the engine and field count while a query searches, e.g. ⌕ regex · 12 fields. Switch to BSON mode (Tab) to see the generated $or.

If the collection has a text index, press Ctrl+T in the query bar to switch search to $text. The terms become one $text: { $search: … }, with each term sent as a quoted phrase so that every term must match, just as in regex mode. $text uses the index, but it matches whole words (stemmed), not substrings, and skips the type-aware matching. Field tokens still combine with it:

alice status:active → { $text: { $search: "\"alice\"" }, status: "active" }

Excluded terms become -"term" inside $search. $text needs at least one positive term, so a query with only excluded terms uses the regex $nor even when $text is on.

The choice is kept per tab. Without a text index, Ctrl+T shows a warning and search stays on regex.

Author:Peter → { "Author": "Peter" }
Author:Peter State:Closed → { "Author": "Peter", "State": "Closed" }
age>25 → { "age": { "$gt": 25 } }
age>=18 age<65 → { "age": { "$gte": 18, "$lt": 65 } }

Use field:lo..hi to express a range with a single token. Either bound can be omitted.

age:18..65 → { "age": { "$gte": 18, "$lte": 65 } }
age:..65 → { "age": { "$lte": 65 } }
age:18.. → { "age": { "$gte": 18 } }
price:10.5..99.99 → { "price": { "$gte": 10.5, "$lte": 99.99 } }

Date strings are automatically coerced to MongoDB ISODate values. YYYY-MM-DD is treated as start-of-day UTC.

createdAt:2025-01-15 → { "createdAt": ISODate("2025-01-15T00:00:00.000Z") }
createdAt>2025-01-01 → { "createdAt": { "$gt": ISODate("2025-01-01T00:00:00.000Z") } }
createdAt>=2025-01-01T12:00:00Z → { "createdAt": { "$gte": ISODate("2025-01-01T12:00:00.000Z") } }
createdAt!=2025-06-15 → { "createdAt": { "$ne": ISODate("2025-06-15T00:00:00.000Z") } }

Date ranges use the same lo..hi shorthand. The upper bound gets end-of-day (23:59:59.999Z) when written as a date-only string.

createdAt:2025-01-01..2025-12-31 → $gte 2025-01-01T00:00:00Z, $lte 2025-12-31T23:59:59.999Z
createdAt:2025-06-01.. → on or after 2025-06-01

Evaluated at query time (UTC). Useful for always-fresh filters.

Expression Meaning
now Current instant
today Start of current UTC day
ago(Nd) N days ago
ago(Nw) N weeks ago
ago(Nm) N calendar months ago
ago(Nh) N hours ago
in(Nd) N days from now
in(Nw) N weeks from now
in(Nm) N calendar months from now
in(Nh) N hours from now
createdAt>ago(7d) → created in the last 7 days
createdAt>today → created since start of today
createdAt:ago(1m)..today → last month up to start of today
expiresAt<in(7d) → expires within the next 7 days
scheduledAt:now..in(1w) → scheduled between now and 7 days from now
-status:deleted → { "status": { "$ne": "deleted" } }
email:null → { "email": null }
email:exists → { "email": { "$exists": true } }
email:!exists → { "email": { "$exists": false } }
name:/^john/i → { "name": { "$regex": "^john", "$options": "i" } }
tags:[admin,user] → { "tags": { "$in": ["admin", "user"] } }
-tags:[spam,bot] → { "tags": { "$nin": ["spam", "bot"] } }
comments:size:0 → { "comments": { "$size": 0 } }
address.city:London → { "address.city": "London" }

Projection tokens are written inline in the same query string.

Token Meaning
+field Include field
-field Exclude field (bare, no value)
Author:Peter +name +email → filter by Author, return only name and email
Author:Peter -_id -tags → filter by Author, exclude _id and tags
+name +score -_id → projection only, no filter

Projection tokens carry through automatically when you switch to BSON mode or the pipeline editor.

With any +path token, the columns are exactly _id plus the included paths, in the order you wrote them. A nested path becomes its own column holding the bare value:

+Status +TvContract.Username → columns _id, Status, TvContract.Username
+items.sku → items.sku shows ["A-1", "B-2", …], one value per array element

Without +path tokens the columns are detected from the documents, as before. A trailing 0/1 $project in a pipeline, and an inclusion in BSON mode’s projection field, flatten the same way.

MongoDB rejects a projection that mixes inclusions and exclusions, so - on a column under +path tokens removes that column’s + token instead of adding a - one.

Press c for a list of every field the schema knows, nested paths indented under their parent, each with its type.

Key Action
typing Filter the fields (fuzzy, full path)
↑ / ↓, Ctrl+P / Ctrl+N Move
Space Show / hide the field
Ctrl+A Show all filtered fields, or hide them if all are shown
Ctrl+X Hide all filtered fields — then pick the few you want with Space
Ctrl+R Back to the default columns
Shift+↑ / Shift+↓ Move the field one column earlier / later
Enter Apply
Esc Discard changes

Fields you check become columns in the order you check them, so Ctrl+X followed by a few Spaces gives exactly those columns, in that order. Enter does nothing while no field is checked.

Showing a.b hides a and the other way around, since MongoDB can’t project a path and its parent together.

On Enter the picker writes the shortest projection that shows your choice: nothing for the default columns, -field tokens when only top-level fields are hidden, or a +path list when a nested path or a custom order needs one, or when that list is shorter. The result is in the query bar like any projection you typed. In pipeline mode it edits the pipeline’s $project stage; in BSON mode, use the projection field.

@<letter> resolves to _id: { $in: [...] } from the marks registered for the active collection. The sigil prefix means the token can never collide with a field literally called marks.

@a → docs marked with letter a
@a Author:Peter → marked-with-a AND Author=Peter
@a +name -_id → marked-with-a, projecting only name
@a @b → last-write wins (applies @b)
Detail Behaviour
Single lowercase letter only @A, @ab, @1 are not recognised
Empty register Resolves to _id: { $in: [] } (matches nothing — explicit, not silent)
Conflict with _id:... Last-write wins, like other field tokens
Pipeline editor @a is expanded to literal ids when opening the pipeline (Ctrl+F / Ctrl+E)

The token is live in simple mode — newly-marked documents surface on the next reload, because @<letter> is resolved at every query parse. BSON and pipeline modes snapshot the resolved ids at the moment '<letter> is pressed; press it again to refresh.

Type @ in the simple query bar to see every used register in the active collection, with its doc count and color.

See the Usage guide for the full marking workflow.