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.
Install the Package:
composer require symfony/ai-mongo-db-store
Ensure mongodb/mongodb (v2.0+) is installed as a dependency.
Configure MongoDB Atlas:
768 for text-embedding-ada-002):
db.your_collection.createIndex({
"vector": "vectorSearch",
"dimensions": 768,
"similarity": "cosine",
"name": "vector_index"
});
Basic Usage in Laravel:
use Symfony\AI\Store\MongoDbStore;
use Symfony\AI\Store\VectorSearchOptions;
// In a service or controller
$client = new \MongoDB\Client(env('MONGODB_ATLAS_URI'));
$store = new MongoDbStore(
$client,
'your_database',
'your_collection',
new VectorSearchOptions(768, 'cosine') // dimensions, similarity metric
);
// Insert an embedding
$store->insert([
'id' => 'doc_123',
'vector' => [0.1, 0.2, ..., 0.768], // Your embedding array
'metadata' => ['title' => 'Example', 'category' => 'tech']
]);
// Query nearest neighbors
$results = $store->findNearest(
[0.5, 0.6, ..., 0.768], // Query vector
5, // Limit
0.8 // Threshold (optional)
);
Laravel Service Provider: Bind the store to the container for dependency injection:
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->singleton(\Symfony\AI\Store\StoreInterface::class, function ($app) {
$client = new \MongoDB\Client(env('MONGODB_ATLAS_URI'));
return new MongoDbStore(
$client,
env('MONGODB_COLLECTION_DB'),
env('MONGODB_COLLECTION_NAME'),
new VectorSearchOptions(768, 'cosine')
);
});
}
Environment Variables:
Add to .env:
MONGODB_ATLAS_URI=mongodb+srv://user:pass@cluster.mongodb.net/...
MONGODB_COLLECTION_DB=your_database
MONGODB_COLLECTION_NAME=your_collection
Generate Embeddings:
Use a model like text-embedding-ada-002 to create embeddings for your documents (e.g., via Laravel HTTP client or a local service).
Store Embeddings:
$store->insert([
'id' => 'doc_456',
'vector' => $embeddingArray,
'metadata' => ['content' => 'Your document text...']
]);
Query:
$queryEmbedding = getEmbedding("user search query");
$results = $store->findNearest($queryEmbedding, 3);
Display Results:
foreach ($results as $result) {
echo $result['metadata']['content']; // Render the matched document
}
findNearest to fetch relevant documents for an LLM prompt.$relevantDocs = $store->findNearest($queryEmbedding, 5);
$context = implode("\n\n", array_map(fn($doc) => $doc['metadata']['content'], $relevantDocs));
$prompt = "Answer the question based on this context: $context\n\nQuestion: $userQuery";
$llmResponse = $openAI->chat($prompt);
findNearest results in PHP using metadata (e.g., category, date).$rawResults = $store->findNearest($queryEmbedding, 10);
$filteredResults = array_filter($rawResults, function ($doc) {
return $doc['metadata']['category'] === 'tech' &&
strtotime($doc['metadata']['date']) > strtotime('-1 year');
});
$bulk = new \MongoDB\Driver\BulkWrite;
foreach ($embeddings as $embedding) {
$bulk->insert([
'id' => $embedding['id'],
'vector' => $embedding['vector'],
'metadata' => $embedding['metadata']
]);
}
$client->selectCollection('your_database', 'your_collection')->bulkWrite($bulk->getOperations());
findNearest thresholds based on use case (e.g., stricter for high-precision tasks).$threshold = request()->input('strict') ? 0.9 : 0.7;
$results = $store->findNearest($queryEmbedding, 5, $threshold);
Queue Jobs for Async Operations:
// Dispatch a job
StoreEmbeddingJob::dispatch($documentId, $embeddingArray);
// Job class
public function handle()
{
$store = app(\Symfony\AI\Store\StoreInterface::class);
$store->insert([...]);
}
Caching Layer:
$cacheKey = "search:{$userQuery}";
$results = cache()->remember($cacheKey, now()->addHours(1), function () use ($queryEmbedding) {
return $store->findNearest($queryEmbedding, 5);
});
Event-Driven Updates:
// In a service
event(new DocumentCreated($document));
// Listener
public function handle(DocumentCreated $event)
{
$embedding = generateEmbedding($event->document->content);
$store->insert([...]);
}
API Resource Transformation:
Resource classes:
class SearchResultResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'content' => $this->metadata['content'],
'score' => $this->score,
];
}
}
Index Management:
explain() to analyze query plans:
$collection->explain('executionStats')->find([...]);
Connection Pooling:
$client = new \MongoDB\Client($uri, [
'pool' => [
'maxSize' => 50,
'minSize' => 10,
],
]);
Atlas Search Integration:
// Atlas Search pipeline stage
{
$search: {
index: "your_search_index",
text: { query: "user query", path: "metadata.content" }
}
}
Vector Dimensions Mismatch:
768 vs. 384) will fail silently or return incorrect results.if (count($vector) !== 768) {
throw new \InvalidArgumentException("Vector must have 768 dimensions.");
}
Atlas Vector Search Beta Limitations:
How can I help you explore Laravel packages today?