AI
Auto Embeddings
Give every document written to a collection a vector for one of its fields, computed by your provider. Under each rule, the steps to a semantic search, and a guided demo on the starter's catalog.
Under AI → Auto Embeddings you add rules that give every document written to a collection a vector for one of its fields. A rule names a text field, the field the vector goes to, and the provider and model that compute it. Your provider bills the calls. A collection may have several rules, for example summary with one model and body with another, each searchable. The rules live in the collection’s vectorSearch metadata, so your own application can write them too.
The page needs a key. Without one, a bar at the top takes you to AI Keys, and back here once the key is saved. With one, the bar shows the provider and model the service embeds with by default.
The rule
Open a collection and Add embedding:
-
Text field: what the vector is computed from. The fields of a stored document are suggested.
-
Vector field: where the vector is stored,
embeddingby default. -
Provider and model: among the providers saved under AI Keys, with the vendor’s models; the default is what the service embeds with.
-
Dimensions: the vector’s length, chosen among what the model allows. A vector index on the field must declare the same.
-
Group by, with a contextual model such as
voyage-context-4: the documents of one write that share this field are embedded together, each vector aware of the others.fileIdfor the chunks of a file, as Auto Chunking writes them.
Save writes the rule into vectorSearch: [ { textField, embeddingField, provider, model, dimensions }, … ] on the collection, beside its other rules: one rule per vector field. Changing the model or the length with Edit warns you first: the stored vectors no longer match new ones, so saving removes them, and the rule then offers to embed the documents again. Remove deletes the rule and leaves the other rules and the vectors in place.
A search uses the rule of the field it searches: $vectorize as the queryVector of a $vectorScan or $vectorSearch reads the stage’s path and embeds the question with that field’s model. Anywhere else, name the field: { "$vectorize": { "text": …, "field": "bodyVector" } }.
Under the rule
Three lines say what the collection still needs to be searchable, and where to do it:
-
Documents: how many have the text and no vector, because they were written before the rule or by something that bypassed it. Embed them patches each one with its own text, and the service embeds it: one call to the provider per document, with a counter. The console does this for up to 1,000 documents, one request at a time, and stops at the first document that gets no vector, with the provider’s error. For more than 1,000, Show a script gives a Python script that runs the same loop from your machine.
-
Search: the aggregation that searches the vectors, if there is one, with Try it to run it on the Aggregations page. Otherwise Add search aggregation opens Aggregations on the collection with the Semantic search preset filled in:
$vectorizeon the parameterq,$vectorScanon the vector field, no index needed, reranked when the service reranks. Save, and you are back here. -
Index: the vector index on the field, if there is one, with its length. Otherwise Add vector index opens Indexes on the collection with the Vector search template filled in, name, field and dimensions. An index is optional:
$vectorScansearches without one, and an index pays off as the collection grows. Vector indexes come with Pro and above; with one, the search switches to$vectorSearch.
Demo setup
Under the list, Demo setup takes you from a rule to a semantic search on catalog, the collection of the ecommerce starter and of the MCP demo, so the agent, the search and the shop use the same products. The demo embeds with a low-cost model from a provider you have a key for: voyage-4-lite with Voyage AI, text-embedding-3-small with OpenAI, the default model with any other. It writes the model on the collection’s rule, so your default stays as you chose. Each step has a checkbox that says whether it is done, and a button. Do all runs the missing steps in order and stops at the first error.
| Step | What it does |
|---|---|
Collection |
Creates the collection if missing, and writes the rule on it with the demo’s model: from then on every product written gets the vector of its description. When the collection’s model differs from the demo’s, the step reads Switch model: it drops the old vectors, and the index if the length changed, and the steps below compute them again. |
Sample products of the ecommerce starter |
Shown only while the collection is empty. Loads a hundred or so products from the starter’s repository, each embedded as it is written. |
Vectors of the products already stored |
Shown only when the collection holds something. Products written before the rule have no vector: each is patched with its own description, and the service embeds it. One call to the provider per product. |
Aggregation |
The question vectorized with |
Vector index |
A |
Then ask: GET /catalog/_aggrs/search?q=a gift for a gardener returns the products closest in meaning to the question.
By hand
Under By hand the same steps are HTTP calls in curl, HTTPie, JavaScript and Python, with a temporary admin token, ready to run. Pick a tool on one block and every block follows. These are the calls your own application makes:
PUT /catalog
{ "vectorSearch": [ { "textField": "description", "embeddingField": "embedding",
"provider": "voyageEmbeddingProvider", "model": "voyage-4-lite", "dimensions": 1024 } ] }
With an OpenAI-compatible provider the rule names it by URL, and the service attaches that provider's key.
A single rule may also be written as the object alone, without the list:
{ "vectorSearch": { "textField": "description", "embeddingField": "embedding",
"provider": "openAIEmbeddingProvider", "base-url": "https://openrouter.ai/api/v1",
"model": "perplexity/pplx-embed-v1-4b", "dimensions": 1024 } }
PATCH /catalog
{ "aggrs": [ { "uri": "search", "type": "pipeline", "stages": [
{ "$vectorScan": { "path": "embedding", "queryVector": { "$vectorize": { "$var": "q" } },
"similarity": "cosine", "limit": 10 } },
{ "$project": { "embedding": 0 } } ] } ] }
GET /catalog/_aggrs/search?q=a%20gift%20for%20a%20gardener
Optional, when the collection grows:
PUT /catalog/_indexes/catalog_vectors
{ "type": "vectorSearch",
"fields": [ { "type": "vector", "path": "embedding", "numDimensions": 1024, "similarity": "cosine" } ] }
and in the search, in place of $vectorScan, with the score MongoDB keeps aside set on each result:
{ "$vectorSearch": { "index": "catalog_vectors", "path": "embedding",
"queryVector": { "$vectorize": { "$var": "q" } }, "numCandidates": 100, "limit": 10 } },
{ "$set": { "score": { "$meta": "vectorSearchScore" } } }
On a collection that already exists, send the first body with PATCH, which merges; PUT replaces all the properties. A vector index takes a few seconds to be ready after it is created; a search before that returns nothing, with no error.
What it costs
Your provider bills every embedding, one per document written and one per question, to your account. Ulabase adds nothing. Embed them and the sample products make one call per document; the page says how many before you click. $vectorScan reads every vector it compares: fine for thousands of documents; for more, add an index.