diff --git a/examples/atlas-search.php b/examples/atlas-search.php
new file mode 100644
index 000000000..938751256
--- /dev/null
+++ b/examples/atlas-search.php
@@ -0,0 +1,133 @@
+selectCollection($databaseName, $collectionName);
+
+$count = $collection->estimatedDocumentCount();
+if ($count === 0) {
+ echo 'This example requires the "', $databaseName, '" database with the "', $collectionName, '" collection.', "\n";
+ echo 'Load the sample dataset in your MongoDB Atlas cluster before running this example:', "\n";
+ echo ' https://www.mongodb.com/docs/atlas/sample-data/', "\n";
+ exit(1);
+}
+
+// Delete the index if it already exists
+$indexes = iterator_to_array($collection->listSearchIndexes());
+foreach ($indexes as $index) {
+ if ($index->name === 'default') {
+ echo "The index already exists. Dropping it.\n";
+ $collection->dropSearchIndex($index->name);
+
+ // Wait for the index to be deleted.
+ wait(function () use ($collection) {
+ echo '.';
+ foreach ($collection->listSearchIndexes() as $index) {
+ if ($index->name === 'default') {
+ return false;
+ }
+ }
+
+ return true;
+ });
+ }
+}
+
+// Create the search index
+echo "\nCreating the index.\n";
+$collection->createSearchIndex(
+ /* The index definition requires a mapping
+ * See: https://www.mongodb.com/docs/atlas/atlas-search/define-field-mappings/ */
+ ['mappings' => ['dynamic' => true]],
+ // "default" is the default index name, this config can be omitted.
+ ['name' => 'default'],
+);
+
+// Wait for the index to be ready.
+wait(function () use ($collection) {
+ echo '.';
+ foreach ($collection->listSearchIndexes() as $index) {
+ if ($index->name === 'default') {
+ return $index->queryable;
+ }
+ }
+
+ return false;
+});
+
+// Perform a text search
+echo "\n", 'Performing a text search...', "\n";
+$results = $collection->aggregate([
+ [
+ '$search' => [
+ 'index' => 'default',
+ 'text' => [
+ 'query' => 'view beach ocean',
+ 'path' => ['name'],
+ ],
+ ],
+ ],
+ ['$project' => ['name' => 1, 'description' => 1]],
+ ['$limit' => 10],
+])->toArray();
+
+foreach ($results as $document) {
+ echo ' - ', $document['name'], "\n";
+}
+
+echo "\n", 'Enjoy MongoDB Atlas Search!', "\n\n";
+
+/**
+ * This function waits until the callback returns true or the timeout is reached.
+ */
+function wait(Closure $callback): void
+{
+ $timeout = hrtime()[0] + WAIT_TIMEOUT_SEC;
+ while (hrtime()[0] < $timeout) {
+ if ($callback()) {
+ return;
+ }
+
+ sleep(5);
+ }
+
+ throw new RuntimeException('Time out');
+}
diff --git a/psalm-baseline.xml b/psalm-baseline.xml
index db2c99aed..fcc5cc66f 100644
--- a/psalm-baseline.xml
+++ b/psalm-baseline.xml
@@ -5,6 +5,30 @@
decrypt($document->encryptedField)]]>
+
+
+
+ name]]>
+
+
+
+
+
+ $document
+ $index
+ $index
+ $index
+
+
+ name]]>
+ name]]>
+ name]]>
+ queryable]]>
+
+
+ $uri
+
+
markTestSkipped('Atlas Search examples are only supported on MongoDB Atlas');
+ }
+
+ $this->skipIfServerVersion('<', '7.0', 'Atlas Search examples require MongoDB 7.0 or later');
+
+ // Generate random collection name to avoid conflicts with consecutive runs as the index creation is asynchronous
+ $collectionName = sprintf('%s.%s', $this->getCollectionName(), bin2hex(random_bytes(5)));
+ $databaseName = $this->getDatabaseName();
+ $collection = $this->createCollection($databaseName, $collectionName);
+ $collection->insertMany([
+ ['name' => 'Ribeira Charming Duplex'],
+ ['name' => 'Ocean View Bondi Beach'],
+ ['name' => 'Luxury ocean view Beach Villa 622'],
+ ['name' => 'Ocean & Beach View Condo WBR H204'],
+ ['name' => 'Bondi Beach Spacious Studio With Ocean View'],
+ ['name' => 'New York City - Upper West Side Apt'],
+ ]);
+ putenv(sprintf('MONGODB_DATABASE=%s', $databaseName));
+ putenv(sprintf('MONGODB_COLLECTION=%s', $collectionName));
+
+ $expectedOutput = <<<'OUTPUT'
+
+Creating the index.
+%s
+Performing a text search...
+ - Ocean View Bondi Beach
+ - Luxury ocean view Beach Villa 622
+ - Ocean & Beach View Condo WBR H204
+ - Bondi Beach Spacious Studio With Ocean View
+
+Enjoy MongoDB Atlas Search!
+
+
+OUTPUT;
+
+ $this->assertExampleOutput(__DIR__ . '/../examples/atlas-search.php', $expectedOutput);
+ }
+
public function testChangeStream(): void
{
$this->skipIfChangeStreamIsNotSupported();