Text, wildcard, geospatial & Atlas search

This section documents the current MongoDB 8.x server line as published at the MongoDB Server Manual, which is the reference these pages are written and verified against. No specific patch version is pinned. Some capabilities (Atlas Search, Atlas Vector Search, and parts of encryption and backup) are Atlas-only — they are linked, not documented in depth.

This content was generated with the assistance of AI and should be verified against the official manual before being relied on in production, since MongoDB iterates quickly.

This section’s bibliography lists the reference material consulted while preparing these pages.

Beyond ordinary single-field and compound indexes, MongoDB has index types built for specific access patterns: full-text matching, unpredictable field names, points and shapes on a sphere, and hash-distributed keys. This page covers each with a runnable example, then points to the Atlas-only search products. For the general index model and explain() see Indexing & query performance.

Text indexes and $text

A text index tokenises string fields (and string elements of arrays) so $text can match by word rather than by exact string. Declare it with the special "text" direction; use "$**" as the field to index every string field. See Text indexes and Text search.

db.articles.createIndex({ title: "text", body: "text" })

db.articles.find({ $text: { $search: "mongodb index" } })   // matches "indexes", "indexing" via stemming

A collection may have only one text index, though that index can span many fields. Use $meta: "textScore" to project and sort by relevance. See $text and $meta.

db.articles.find(
  { $text: { $search: "mongodb index" } },
  { score: { $meta: "textScore" }, title: 1 }
).sort({ score: { $meta: "textScore" } })

The index’s default_language sets the stemming and stop-word rules; a per-document language field can override it. weights scale each field’s contribution to the score, so a match in the title can outrank a match in the body.

db.articles.createIndex(
  { title: "text", body: "text" },
  { default_language: "english", weights: { title: 10, body: 1 } }
)

The built-in text index is adequate for simple keyword lookup. For real search workloads — relevance tuning, analyzers, autocomplete, faceting, fuzzy matching — Atlas Search and Atlas Vector Search supersedes it and is the recommended path on Atlas.

Wildcard indexes

A wildcard index uses the "$**" key to index fields whose names are not known in advance — an attribute bag such as attributes.color, attributes.ramGb, attributes.warrantyMonths that differs per document. wildcardProjection restricts it to (or excludes) a sub-tree. See Wildcard indexes.

db.products.createIndex({ "attributes.$**": 1 })

db.products.find({ "attributes.color": "blue" })          // uses the wildcard index
db.products.find({ "attributes.ramGb": { $gte: 16 } })    // and so does this

Trade-offs: a wildcard index can be large (one entry per indexed leaf field per document) and slows writes accordingly; it supports only one queried field at a time (it is not a substitute for a compound index); it cannot back a sort on an unspecified field; and it never covers a query. Reach for it only when the field names really are open-ended — otherwise name the fields in an ordinary index.

Geospatial indexes

A 2dsphere index indexes points and shapes stored as GeoJSON objects on an Earth-like sphere, so distances and containment are computed correctly across the globe. It supports $near / $nearSphere (nearest-first, optionally bounded by $maxDistance in metres), $geoWithin (inside a polygon), and $geoIntersects (shares any point with a geometry). See Geospatial queries and 2dsphere indexes.

db.places.insertOne({
  name: "Cafe",
  location: { type: "Point", coordinates: [ -3.7038, 40.4168 ] }   // [ longitude, latitude ]
})
db.places.createIndex({ location: "2dsphere" })

// Nearest places within 1 km
db.places.find({
  location: {
    $nearSphere: {
      $geometry: { type: "Point", coordinates: [ -3.7038, 40.4168 ] },
      $maxDistance: 1000
    }
  }
})

// Places inside a neighbourhood polygon
db.places.find({
  location: {
    $geoWithin: {
      $geometry: { type: "Polygon", coordinates: [ [ [ -3.71, 40.41 ], [ -3.69, 40.41 ], [ -3.69, 40.43 ], [ -3.71, 40.43 ], [ -3.71, 40.41 ] ] ] }
    }
  }
})

The legacy 2d index indexes coordinate pairs on a flat plane ([ x, y ] legacy pairs, not GeoJSON). Use it only for planar data such as a game map or floor plan, not for points on the Earth. See 2d indexes.

db.board.createIndex({ pos: "2d" })
db.board.find({ pos: { $geoWithin: { $box: [ [ 0, 0 ], [ 100, 100 ] ] } } })

Hashed indexes

A hashed index stores the hash of a single field’s value rather than the value itself. Its main use is a hashed shard key, which spreads monotonically increasing keys (such as ObjectId or a timestamp) evenly across shards instead of piling every new document onto one chunk. Hashed indexes support equality matches but not range queries or sorts on the field. See Hashed indexes, and for how a shard key is chosen see Sharding.

db.events.createIndex({ _id: "hashed" })
sh.shardCollection("app.events", { _id: "hashed" })

These are Atlas-only services — available on MongoDB Atlas, not in the self-managed server — so they are described here only in outline.

Atlas Search embeds an Apache Lucene index alongside the collection and exposes it through the $search aggregation stage. It provides analyzers, relevance scoring, fuzzy matching, autocomplete, highlighting, and facets — the capabilities the built-in text index lacks — and stays in sync with the collection automatically. Use it for user-facing full-text search. See Atlas Search.

Atlas Vector Search indexes dense vector embeddings and exposes approximate nearest-neighbour queries through the $vectorSearch stage, for semantic search, recommendations, and retrieval-augmented generation. You generate embeddings with an external model, store them as an array field, and query with a query vector through $vectorSearch. See Atlas Vector Search and the $vectorSearch stage reference for the full syntax.