Search
Search a term in several fields, with MongoDB's text search, MongoDB Search, or mz.term for a search box without either.
A search box sends a term, and the app looks for it in several fields of each document. MongoDB has
two ways of its own, and mz.term covers the case neither does:
| Need | Use | Runs on |
|---|---|---|
| Whole words, without case or accents, ranked by relevance | $text | Every MongoDB, with a text index |
| Search while typing, parts of words, typos | $search | MongoDB Search: Atlas, or a self-managed 8.2 or later, in preview |
| Search while typing, parts of words, without MongoDB Search | mz.term | Every MongoDB, without an index |
$text
A text index covers several fields, and $text matches whole words in any of them, without
telling case or accents apart. A collection takes one text index. Words are alternatives, and each
one in quotes is required:
import { ObjectId } from 'mongodb'
import { mongozod } from 'mongozod'
import * as mz from 'mongozod/mzod'
import * as z from 'zod'
const noteSchema = z.object({
_id: mz.objectId()
.default(() => new ObjectId()),
title: z.string(),
content: z.string(),
organization: z.string()
})
const NotesModel = mongozod({
collection: 'notes',
db,
schema: noteSchema,
indexes: (index) => [
index({ title: 'text', content: 'text' }, { default_language: 'none' })
]
})
// Notes with "cafe" or "leche" in the title or the content, such as `Café con leche`.
await NotesModel.find({ $text: { $search: 'cafe leche' } })
// Notes with both words.
await NotesModel.find({ $text: { $search: '"cafe" "leche"' } })$text matches the complete word: desay does not find Desayuno, so it does not suit a box that
searches while the user types. default_language: 'none' matches the words as written; a language,
such as spanish, also matches their stems
(MongoDB docs).
$search
MongoDB Search indexes the fields apart, and
$search, the first stage of an aggregate, finds parts of words with autocomplete, folds
accents with the icuFolding token filter and tolerates typos. It runs on Atlas and, from MongoDB
8.2, on a self-managed server with the mongot process, in public preview: MongoDB recommends that
one for testing, not for production. Its indexes are search indexes, which sync() does not
create.
const found = await NotesModel.aggregate([
{ $search: { index: 'notes', autocomplete: { query: 'desay', path: 'title' } } },
{ $limit: 20 }
])mz.term
Without MongoDB Search, mz.term turns the term into a filter with a
$regex per word and field: each word has to appear in one of the declared fields, as part of a
word, without telling case or accents apart. The client sends text, never a pattern: the builder
escapes it.
const listNotesSchema = z.object({
filter: mz
.filter(noteSchema, {
organization: []
})
.required({ organization: true }),
term: z.string()
.max(100)
.optional()
.pipe(mz.term(noteSchema, { title: true, content: true }))
})
const { filter, term } = listNotesSchema.parse({ filter: { organization: 'acme' }, term: 'desay' })
await NotesModel.find({ $and: [filter, term] }, { maxTimeMS: 2000 })
// Finds a note whose content says `Desayuno de la mañana`- Length: limit the term with Zod, as
.max(100)above. Each word adds a$regexper field. - Cost: a
$regexthat ignores case uses no index. It reads every document that the rest of the filter leaves, so filter by an indexed field too, such as the organization, and passmaxTimeMS. - The text: after parsing,
termis the filter. Code that needs the text, such as a client that highlights it, reads it from the input before parsing. - Accents: the Latin letters match their accented forms, such as
awithá,äandã, andnwithñ, in both directions. Letters with no decomposition, such asøorß, match only themselves.
Common mistakes
- A
$regexbuilt from the client's text without escaping it: a[makes the server fail, and.matches everything. Usemz.term, or escape it. $textfor a box that searches while typing: it finds nothing until the word is complete.$searchon a self-managed server in production: it is in preview there. Usemz.term, or move to Atlas.
Last updated on
MongoZod is an independent open-source project. It is not affiliated with, endorsed by or sponsored by MongoDB, Inc. MongoDB® is a registered trademark of MongoDB, Inc.