symfony/ai-mongo-db-store
Integrates MongoDB Atlas Vector Search ($vectorSearch) as a vector store for Symfony AI Store, enabling storage and similarity search over embeddings using Atlas. Designed for use with MongoDB Atlas and the Symfony AI ecosystem.
composer require symfony/ai-mongo-db-store mongodb/mongodb
db.embeddings.createIndex({
"vector": "vectorSearch",
"dimensions": 768, // Match your embedding dimension
"similarity": "cosine" // or 'euclidean', 'dotProduct'
});
use Symfony\AI\Store\MongoDbStore;
use MongoDB\Client;
$client = new Client(env('MONGODB_ATLAS_URI'));
$store = new MongoDbStore(
$client->selectDatabase('your_db'),
'embeddings',
new \Symfony\AI\Store\MongoDbStore\VectorSearchOptions(768, 'cosine')
);
// Insert an embedding
$store->insert('doc_id', [0.1, 0.2, ...]); // 768-dim vector
// Query nearest neighbors
$results = $store->findNearest('query_vector', 5);
Replace a keyword search with vector-based retrieval:
// Generate embeddings (e.g., with Symfony AI's embedder)
$embedding = $embeddingService->embed("user query");
// Retrieve top 3 semantically similar documents
$similarDocs = $store->findNearest($embedding, 3);
// Use results in your app (e.g., populate search results)
foreach ($similarDocs as $doc) {
$content = $documentRepository->find($doc['id'])->getContent();
// ...
}
// Laravel Service Example
public function search(string $query, int $limit = 5) {
$embedding = $this->embeddingService->embed($query);
$ids = $this->vectorStore->findNearest($embedding, $limit)
->map(fn ($item) => $item['id']);
return $this->documentRepository->findByIds($ids);
}
$match for filtering:
$query = [
'$vectorSearch' => [
'queryVector' => $embedding,
'path' => 'vector',
'numCandidates' => 100,
'limit' => 5,
'index' => 'vector_index'
],
'$match' => ['category' => 'books', 'publishedAfter' => new \MongoDB\BSON\UTCDateTime('2020-01-01')]
];
$cursor = $this->collection->aggregate([$query]);
public function register() {
$this->app->singleton(MongoDbStore::class, function ($app) {
return new MongoDbStore(
new Client(env('MONGODB_ATLAS_URI')),
env('MONGODB_COLLECTION'),
new VectorSearchOptions(768, 'cosine')
);
});
}
$bulk = $this->collection->initializeUnorderedBulkOp();
foreach ($documents as $doc) {
$bulk->insert([
'id' => $doc['id'],
'vector' => $doc['embedding'],
'metadata' => $doc['metadata']
]);
}
$bulk->execute();
$cacheKey = "recommendations:{$userId}";
$recommendations = cache()->remember($cacheKey, now()->addHours(1), function () use ($userId) {
return $this->vectorStore->findNearest($this->getUserEmbedding($userId), 10);
});
| Pattern | Implementation |
|---|---|
| RAG (Retrieval-Augmented Generation) | Use findNearest to fetch context for LLMs: |
| ```php | |
| $context = $this->vectorStore->findNearest($queryEmbedding, 3) | |
| ->map(fn ($item) => $item['metadata']['content']); | |
| $response = $llm->generate($prompt . "\nContext: " . implode("\n", $context)); | |
| ``` | |
| Dynamic Filtering | Pass filters via findNearest’s filter option: |
| ```php | |
| $results = $store->findNearest($embedding, 5, [ | |
| 'filter' => ['category' => 'electronics', 'price' => ['$lt' => 100]] | |
| ]); | |
| ``` | |
| Vector Updates | Re-insert or use $set for partial updates: |
| ```php | |
| $this->collection->updateOne( | |
| ['id' => 'doc_id'], | |
| ['$set' => ['vector' => $newEmbedding]] | |
| ); |
Index Mismatch Errors:
Invalid dimensions or similarity metric not supported.VectorSearchOptions match your Atlas index:
// Atlas index: dimensions=768, similarity=cosine
$store = new MongoDbStore(..., new VectorSearchOptions(768, 'cosine'));
db.embeddings.getIndexes();
Connection Timeouts:
// config/services.php
'mongodb.connection' => env('MONGODB_LOCAL_URI', env('MONGODB_ATLAS_URI')),
Vector Dimension Mismatch:
Error: Vector dimension mismatch when inserting.if (count($embedding) !== 768) {
throw new \InvalidArgumentException("Embedding must be 768-dimensional.");
}
Filter Syntax:
$gt vs. >).MongoDB\BSON class:
$filter = [
'price' => ['$gt' => 50],
'category' => 'books'
];
Rate Limiting:
$explain to analyze performance:
$explanation = $this->collection->aggregate([
['$vectorSearch' => [...]],
['$limit' => 1]
], ['explain' => true]);
php.ini:
mongodb.log.appendOnly = true
mongodb.log.path = /var/log/mongodb.log
\Symfony\Component\Debug\Debug::dump($store->getCollection()->getManager()->getDatabase()->getClient());
Environment Variables:
.env:
MONGODB_ATLAS_URI=mongodb+srv://user:pass@cluster.mongodb.net/db?retryWrites=true
MONGODB_COLLECTION=embeddings
config/mongodb.php for centralized config:
'connections' => [
'atlas' => [
'uri' => env('MONGODB_ATLAS_URI'),
'database' => env('MONGODB_DATABASE', 'vector_db'),
'options' => [
'retryWrites' => true,
'retryReads' => true,
],
],
],
Atlas-Specific Settings:
How can I help you explore Laravel packages today?