Create a vector search index¶
Before running vector search queries, create a vector search index on the field that contains your embeddings. Use the db.collection.createSearchIndex() method to create a vector search index.
Important
These examples use embeddings stored in the sample documents. The embeddings are created manually rather than generated by Percona Search for MongoDB.
Create a vector search index¶
Follow these steps to create and query a vector search index.
-
Create a vector search index:
db.<collection>.createSearchIndex( <name>, <type>, { <definition> } )createSearchIndex()accepts these fields:Field Type Required Description typestringYes Set to vectorto index an embeddings field, orfilterto index a field used for pre-filtering.pathstringYes The document field that contains the embeddings to index. numDimensionsintYes Number of dimensions in the indexed vectors. Must match the number of dimensions in your embeddings. similaritystringYes Similarity metric used to compare vectors. Use euclidean,cosine, ordotProduct.quantizationstringOptional Compresses indexed vectors to reduce storage and memory use. Use scalarorbinary.Example: Create a vector search index named
vector_idxdb.docs.createSearchIndex( "vector_idx", "vectorSearch", { fields: [ { type: "vector", path: "embedding", numDimensions: 3, similarity: "cosine" } ] } )The example above specifies that:
- The
embeddingfield contains the vectors to index. - Each vector has three dimensions.
- Vector similarity is calculated using cosine similarity.
- The
-
Verify that the index is ready.
db.<collection>.getSearchIndexes(<name>)getSearchIndexes()accepts this field:Field Type Required Description namestringOptional Name of a specific index to return. If omitted, returns all search indexes on the collection. Example
db.docs.getSearchIndexes()Index creation runs asynchronously. Wait until the index status is
READYbefore running vector search queries.Output:
[ { id: '69ebbabd651bce4d10f57be5', name: 'vector_idx', status: 'READY', queryable: true, latestDefinitionVersion: { version: 0, createdAt: ISODate('2026-04-24T18:47:25.000Z') }, latestDefinition: { fields: [ { type: 'vector', path: 'embedding', numDimensions: 3, similarity: 'cosine' } ] }, statusDetail: [ { hostname: '69eb5fc573906b6bfb8cefe7', status: 'READY', queryable: true, mainIndex: { status: 'READY', queryable: true, definitionVersion: { version: 0, createdAt: ISODate('2026-04-24T18:47:25.000Z') }, definition: { fields: [ { type: 'vector', path: 'embedding', numDimensions: 3, similarity: 'cosine' } ] } } } ] } ] -
Run a vector search.
db.<collection>.aggregate([ { $vectorSearch: { index: "<index-name>", path: "<vector-field>", queryVector: <query-vector>, numCandidates: <number>, limit: <number> } } ])$vectorSearchaccepts these fields:Field Required Description indexRequired Name of the vector search index to query. pathRequired Document field that holds the embeddings. Must match the pathin the index definition.queryVectorRequired The vector to search with. Must have the same number of dimensions as the indexed embeddings. limitRequired Maximum number of documents to return. numCandidatesRequired for approximate search Number of candidate vectors to consider before selecting results. A higher value can improve accuracy but takes longer. Set it well above limit, at least 20 times higher as a starting point.filterOptional Limits which documents are considered before the vector comparison runs. exactOptional Set to trueto run an exact nearest neighbor search instead of approximate.For the complete field reference, including filtering and exact nearest neighbor search, see Query with
$vectorSearch.Example
db.docs.aggregate([ { $vectorSearch: { index: "vector_idx", queryVector: [0.3, 0.2, 0.3], path: "embedding", numCandidates: 10, limit: 2 } }, { $project: { _id: 0, text: 1, embedding: 1, score: { $meta: "vectorSearchScore" } } } ])What happens under the hood
When you create the index
mongodreceives the index definition and forwards it tomongot. The definition is stored as metadata in MongoDB.mongotowns the index data.mongotreads theembeddingfield from the documents in the collection and builds a Hierarchical Navigable Small World (HNSW) graph. This structure is what makes approximate nearest neighbor search fast.- The build is asynchronous, so
createSearchIndex()returns before it completes. - After that,
mongotwatches the collection through a change stream and applies later inserts, updates, and deletes to the index.
When you run a query
mongodparses the aggregation pipeline and hands the$vectorSearchstage tomongot.mongotsearches the HNSW graph and returns the identifiers of the matching documents, each with a score. It does not hold your documents, only the index.mongodthen pairs those identifiers with the documents in the collection and passes the result through the rest of the pipeline. The search returns the documents whose embeddings are nearest toqueryVector, closest match first.$projectshapes that output. Thescorefield comes from$meta: "vectorSearchScore". Percona Search for MongoDB calculates the score during the exchange described above and does not store it in the document, which is why you read it as metadata rather than as a field. A higher score means a closer match.