Skip to content
Rate this page
Thanks for your feedback
Thank you! The feedback has been submitted.

Get free database assistance or contact our experts for personalized support.

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.

  1. Create a vector search index:

    db.<collection>.createSearchIndex(
      <name>,
      <type>,
      {
        <definition>
      }
    )
    

    createSearchIndex() accepts these fields:

    Field Type Required Description
    type string Yes Set to vector to index an embeddings field, or filter to index a field used for pre-filtering.
    path string Yes The document field that contains the embeddings to index.
    numDimensions int Yes Number of dimensions in the indexed vectors. Must match the number of dimensions in your embeddings.
    similarity string Yes Similarity metric used to compare vectors. Use euclidean, cosine, or dotProduct.
    quantization string Optional Compresses indexed vectors to reduce storage and memory use. Use scalar or binary.
    Example: Create a vector search index named vector_idx
    db.docs.createSearchIndex(
    "vector_idx",
    "vectorSearch",
    {
        fields: [
        {
            type: "vector",
            path: "embedding",
            numDimensions: 3,
            similarity: "cosine"
        }
        ]
    }
    )
    

    The example above specifies that:

    • The embedding field contains the vectors to index.
    • Each vector has three dimensions.
    • Vector similarity is calculated using cosine similarity.
  2. Verify that the index is ready.

    db.<collection>.getSearchIndexes(<name>)
    

    getSearchIndexes() accepts this field:

    Field Type Required Description
    name string Optional 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 READY before 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'
                }
                ]
            }
            }
        }
        ]
    }
    ]
    
  3. Run a vector search.

    db.<collection>.aggregate([
      {
        $vectorSearch: {
          index: "<index-name>",
          path: "<vector-field>",
          queryVector: <query-vector>,
          numCandidates: <number>,
          limit: <number>
        }
      }
    ])
    

    $vectorSearch accepts these fields:

    Field Required Description
    index Required Name of the vector search index to query.
    path Required Document field that holds the embeddings. Must match the path in the index definition.
    queryVector Required The vector to search with. Must have the same number of dimensions as the indexed embeddings.
    limit Required Maximum number of documents to return.
    numCandidates Required 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.
    filter Optional Limits which documents are considered before the vector comparison runs.
    exact Optional Set to true to 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

    1. mongod receives the index definition and forwards it to mongot. The definition is stored as metadata in MongoDB. mongot owns the index data.
    2. mongot reads the embedding field 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.
    3. The build is asynchronous, so createSearchIndex() returns before it completes.
    4. After that, mongot watches the collection through a change stream and applies later inserts, updates, and deletes to the index.

    When you run a query

    1. mongod parses the aggregation pipeline and hands the $vectorSearch stage to mongot.
    2. mongot searches the HNSW graph and returns the identifiers of the matching documents, each with a score. It does not hold your documents, only the index.
    3. mongod then 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 to queryVector, closest match first.
    4. $project shapes that output. The score field 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.

Next steps

Update a search index

Delete a search index

Learn more

$vectorSearch aggregation stage