= Auto Embeddings :nav-title: Auto Embeddings :description: A rule per collection that gives every written document a vector for one of its fields, computed by your provider; under the rule, the steps to a semantic search, and a guided demo on the starter's catalog. :keywords: auto embedding, vectorSearch metadata, embedding field, $vectorScan, $vectorize, semantic search, vector index, RAG on MongoDB :group: AI :order: 25 Under **AI → Auto Embeddings** every collection of the service is listed, and each one may carry a rule: a text field, the field the vector goes to, and the provider and model that compute it. From then on, every document written with that text gets its vector, on your provider's bill. The rule lives in the collection's `vectorSearch` metadata, so your own application can write it too. The page needs a key: without one, a bar at the top says so and takes you to xref:ai-keys.adoc[AI Keys], and back here once the key is saved. With one, the bar says which 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, `embedding` by 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. **Save** writes `vectorSearch: { textField, embeddingField, provider, model, dimensions }` on the collection. **Edit** with another model or length warns first: the vectors already stored compare with nothing, so saving unsets them, and the rule then offers to embed the documents again. **Remove** forgets the rule and leaves the vectors where they are. One rule per collection for now; the page is built for several. == Under the rule Three lines say what is still missing for the collection to be searchable, and where it is done: * **Documents**: how many have the text and no vector, written before the rule or by something that bypassed it. **Embed them** patches each one with its own text, which is enough for the service to embed it: one call to the provider per document, with a counter. * **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: `$vectorize` on the parameter `q`, `$vectorScan` on 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: `$vectorScan` searches without one, and pays off as the collection grows. It needs a cluster with vector search; the search then 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 xref:mcp.adoc#demo-setup[MCP demo]: the same products for the agent, the search and the shop. The demo embeds with a cheap model of a vendor you have a key for, `voyage-4-lite` with Voyage AI, `text-embedding-3-small` with OpenAI, the default model with any other provider, and writes it on the collection's rule: the default stays what you chose. Each step has a checkbox that says whether the thing exists, a button, and **Do all** runs the missing ones in order, stopping at the first error. [cols="1,2"] |=== | Step | What it does | Collection `catalog` with auto-embedding on `description` | 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 when 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 none: each is patched with its own description, which is enough for the service to embed it. One call to the provider per product. | Aggregation `search`, published on MCP | The question vectorized with `$vectorize` from the parameter `q`, then `$vectorScan` over the vectors, or `$vectorSearch` on the index once there is one. With a reranking model saved, a `rerank` block keeps the best five of the ten closest. Published on MCP with its parameter, so an agent can run it. | Vector index `catalog_vectors`, optional | A `vectorSearch` index on `embedding`, cosine similarity, with the dimensions of the demo's model. Where the cluster has vector search; the search step then reads **Rewrite**, to switch it to `$vectorSearch`. |=== 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 in them, so each one runs as it is. Pick a tool on one block and every block follows. The calls are the ones your own application makes: [source] ---- 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: { "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: { "$vectorSearch": { "index": "catalog_vectors", "path": "embedding", "queryVector": { "$vectorize": { "$var": "q" } }, "numCandidates": 100, "limit": 10 } } ---- On a collection that already exists, send the first body with `PATCH`: `PUT` replaces the whole set of properties, `PATCH` merges. A vector index takes a few seconds to be ready after it is created; a search before that returns nothing, without an error. == What it costs The provider bills every embedding, one per document written and one per question, to your account. RESTHeart Cloud adds nothing. **Embed them** and the sample products embed one document per call; the page says how many before you click. `$vectorScan` reads the vectors it compares on your service: fine for thousands of documents, an index for more.