PHP code example of phpdot / mongodb

1. Go to this page and download the library: Download phpdot/mongodb library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

phpdot / mongodb example snippets


use PHPdot\MongoDB\MongoConnection;
use PHPdot\MongoDB\Config\MongoConfig;
use PHPdot\MongoDB\Database\Database;

$connection = new MongoConnection(new MongoConfig(
    hosts: 'localhost',
    database: 'myapp',
));
$connection->connect();

$db = new Database($connection);
$users = $db->collection('users');

// Insert
$users->insertOne(['name' => 'Omar', 'email' => '[email protected]']);

// Find
$user = $users->findOne(['email' => '[email protected]']);
echo $user->name; // 'Omar'

// Fluent query
$active = $users->find()
    ->filter(['status' => 'active'])
    ->sort(['created_at' => -1])
    ->limit(10)
    ->execute();

foreach ($active as $doc) {
    echo $doc->name;
}

$config = new MongoConfig(
    hosts: 'localhost',                    // string or list of strings
    port: 27017,                           // default port (ignored if host database
    deployment: 'single',                  // 'single', 'replicaSet', 'sharded'
    replicaSet: '',                        // replica set name
    timeoutMs: 1000,                       // connection timeout
    readPreference: 'primary',             // read preference mode
    writeConcern: 'majority',              // string or int
    readConcern: 'local',                  // read concern level
    maxStalenessSeconds: -1,               // -1 = no limit
    tags: [],                              // tag sets for read preference
    retryWrites: true,                     // retryable writes
    retryReads: true,                      // retryable reads
    maxRetries: 3,                         // reconnection retry attempts
    options: [],                           // additional MongoDB URI options
);

$config = new MongoConfig(
    hosts: ['mongo1.example.com', 'mongo2.example.com:27018'],
    database: 'myapp',
);
// URI: mongodb://mongo1.example.com:27017,mongo2.example.com:27018

$config = new MongoConfig(
    hosts: 'mongo.example.com',
    username: 'admin',
    password: 'p@ss w0rd!',   // auto URL-encoded
    database: 'myapp',
);
// URI: mongodb://admin:p%40ss%20w0rd%[email protected]:27017

$connection = new MongoConnection($config);

$connection->connect();         // connect with exponential backoff retries
$connection->isConnected();     // local flag check (no server round-trip)
$connection->ping();            // actual server ping
$connection->ensureConnected(); // throws ConnectionException if not connected
$connection->reconnect();       // close + connect
$connection->close();           // disconnect

$connection->getClient();       // MongoDB\Client
$connection->getDatabase();     // MongoDB\Database (uses config database)
$connection->getConfig();       // MongoConfig

// Single server
new MongoConfig(hosts: 'localhost', database: 'myapp');

// Replica set
new MongoConfig(
    hosts: ['rs1.example.com', 'rs2.example.com', 'rs3.example.com'],
    deployment: 'replicaSet',
    replicaSet: 'rs0',
    readPreference: 'secondaryPreferred',
);

// Sharded cluster
new MongoConfig(
    hosts: ['mongos1.example.com', 'mongos2.example.com'],
    deployment: 'sharded',
);

$db = new Database($connection);
$db = new Database($connection, $logger); // with query logging

$users = $db->collection('users');        // Collection instance

$result = $db->transaction(function (Database $db, Session $session) {
    $db->collection('accounts')->updateOne()
        ->filter(['_id' => $from])
        ->update(['$inc' => ['balance' => -100]])
        ->session($session)
        ->execute();

    $db->collection('accounts')->updateOne()
        ->filter(['_id' => $to])
        ->update(['$inc' => ['balance' => 100]])
        ->session($session)
        ->execute();

    return 'transferred';
});
// $result === 'transferred'

// Transaction options
$db->transaction($callback, [
    'readConcern' => new ReadConcern('snapshot'),
    'writeConcern' => new WriteConcern('majority'),
]);

$result = $db->command(['ping' => 1]);
// ['ok' => 1]

$result = $db->command(['serverStatus' => 1]);

$db->createCollection('users');
$db->createCollection('validated', [
    'validator' => [
        '$jsonSchema' => [
            'bsonType' => 'object',
            'type' => 'collection', 'options' => []], ...]

$db->raw(); // MongoDB\Database escape hatch

// Single document
$result = $users->insertOne(['name' => 'Omar', 'email' => '[email protected]']);
$result->getInsertedId();    // ObjectId
$result->getInsertedCount(); // 1

// Custom ID
$users->insertOne(['_id' => new ObjectId(), 'name' => 'Omar']);

// Multiple documents
$result = $users->insertMany([
    ['name' => 'Alice', 'age' => 25],
    ['name' => 'Bob', 'age' => 30],
    ['name' => 'Charlie', 'age' => 35],
]);
$result->getInsertedCount(); // 3
$result->getInsertedIds();   // [ObjectId, ObjectId, ObjectId]

// Find one — returns Document or null
$user = $users->findOne(['email' => '[email protected]']);
$user = $users->findOne(); // first document in collection

// With options
$user = $users->findOne(
    ['name' => 'Omar'],
    ['projection' => ['name' => 1, 'email' => 1, '_id' => 0]],
);

// Full example
$cursor = $users->find()
    ->filter(['status' => 'active'])           // array filter
    ->projection(['name' => 1, 'email' => 1])  // fields to return
    ->sort(['created_at' => -1, 'name' => 1])  // sort order
    ->limit(10)                                 // max documents
    ->skip(20)                                  // pagination offset
    ->hint('status_1_created_at_-1')            // index hint (string or array)
    ->collation(['locale' => 'en', 'strength' => 2])
    ->maxTimeMS(5000)                           // timeout
    ->batchSize(100)                            // cursor batch size
    ->allowDiskUse()                            // large sorts
    ->comment('admin dashboard query')          // profiler comment
    ->session($session)                         // transaction session
    ->option('noCursorTimeout', true)           // any additional option
    ->execute();                                // → Cursor of Documents

// Iterate results
foreach ($cursor as $doc) {
    echo $doc->name;
}

// Shortcuts
$first = $users->find()->filter(['status' => 'active'])->first(); // Document|null
$count = $users->find()->filter(['status' => 'active'])->count(); // int
$plan  = $users->find()->filter(['status' => 'active'])->explain(); // array

// Filter builder callback
$users->find()
    ->where(fn(Filter $f) => $f
        ->eq('status', 'active')
        ->gte('age', 18)
        ->in('tags', ['vip', 'premium'])
        ->or(
            Filter::new()->eq('role', 'admin'),
            Filter::new()->gt('score', 90),
        )
    )
    ->sort(['score' => -1])
    ->limit(20)
    ->execute();

// Debug compiled state
$query = $users->find()->filter(['status' => 'active'])->sort(['name' => 1]);
$query->getFilter();  // ['status' => 'active']
$query->getOptions(); // ['sort' => ['name' => 1]]

// Update one
$result = $users->updateOne()
    ->filter(['email' => '[email protected]'])
    ->update(['$set' => ['name' => 'Omar H.'], '$inc' => ['logins' => 1]])
    ->execute();

$result->getMatchedCount();  // 1
$result->getModifiedCount(); // 1

// Update with where callback
$users->updateOne()
    ->where(fn(Filter $f) => $f->eq('status', 'inactive')->lt('last_login', $threshold))
    ->update(['$set' => ['archived' => true]])
    ->execute();

// Upsert (insert if not found)
$users->updateOne()
    ->filter(['email' => '[email protected]'])
    ->update(['$set' => ['name' => 'New User']])
    ->upsert()
    ->execute();

// Update many
$result = $users->updateMany()
    ->filter(['status' => 'trial'])
    ->update(['$set' => ['status' => 'expired']])
    ->execute();

// Array filters for positional operators
$users->updateOne()
    ->filter(['_id' => $id])
    ->update(['$set' => ['items.$[elem].qty' => 0]])
    ->arrayFilters([['elem.status' => 'inactive']])
    ->execute();

// Options
$users->updateOne()
    ->filter(['_id' => $id])
    ->update(['$set' => ['name' => 'Omar']])
    ->hint('email_1')
    ->collation(['locale' => 'en'])
    ->session($session)
    ->option('bypassDocumentValidation', true)
    ->execute();

// Debug
$query = $users->updateOne()->filter(['x' => 1])->update(['$set' => ['y' => 2]])->upsert();
$query->getFilter();  // ['x' => 1]
$query->getUpdate();  // ['$set' => ['y' => 2]]
$query->getOptions(); // ['upsert' => true]

// Delete one
$result = $users->deleteOne()
    ->filter(['email' => '[email protected]'])
    ->execute();

$result->getDeletedCount(); // 1

// Delete with where callback
$sessions->deleteMany()
    ->where(fn(Filter $f) => $f->lt('expires_at', new UTCDateTime()))
    ->execute();

// Options
$users->deleteOne()
    ->filter(['_id' => $id])
    ->hint('email_1')
    ->collation(['locale' => 'en'])
    ->session($session)
    ->option('comment', 'cleanup')
    ->execute();

$result = $users->replaceOne(
    ['email' => '[email protected]'],                           // filter
    ['name' => 'Omar', 'email' => '[email protected]', 'v' => 2], // replacement
);

$result->getMatchedCount();  // 1
$result->getModifiedCount(); // 1

// Find and update
$doc = $users->findOneAndUpdate(
    ['email' => '[email protected]'],
    ['$set' => ['last_login' => new UTCDateTime()]],
);
// $doc is the document BEFORE the update (or null if not found)

// Return the document AFTER update
$doc = $users->findOneAndUpdate(
    ['email' => '[email protected]'],
    ['$inc' => ['visits' => 1]],
    ['returnDocument' => \MongoDB\Operation\FindOneAndUpdate::RETURN_DOCUMENT_AFTER],
);

// Find and replace
$doc = $users->findOneAndReplace(
    ['email' => '[email protected]'],
    ['name' => 'Omar', 'email' => '[email protected]'],
);

// Find and delete
$doc = $users->findOneAndDelete(['status' => 'expired']);
// $doc is the deleted document (or null)

$result = $users->bulkWrite([
    ['insertOne' => [['name' => 'New', 'age' => 20]]],
    ['updateOne' => [['name' => 'Existing'], ['$set' => ['active' => true]]]],
    ['updateMany' => [['status' => 'trial'], ['$set' => ['status' => 'expired']]]],
    ['replaceOne' => [['name' => 'Old'], ['name' => 'Replaced']]],
    ['deleteOne' => [['name' => 'Remove']]],
    ['deleteMany' => [['status' => 'deleted']]],
]);

$result->getInsertedCount();
$result->getMatchedCount();
$result->getModifiedCount();
$result->getDeletedCount();
$result->getUpsertedCount();

// Count with filter
$total = $users->countDocuments();
$active = $users->countDocuments(['status' => 'active']);

// Estimated count (fast, metadata-based — no filter)
$approx = $users->estimatedDocumentCount();

// Distinct values
$statuses = $users->distinct('status');
// ['active', 'inactive', 'suspended']

$names = $users->distinct('name', ['status' => 'active']);
// ['Alice', 'Bob', 'Omar']

// Raw pipeline arrays
$results = $orders->aggregate([
    ['$match' => ['status' => 'completed']],
    ['$group' => [
        '_id' => '$category',
        'total' => ['$sum' => '$amount'],
        'count' => ['$sum' => 1],
    ]],
    ['$sort' => ['total' => -1]],
    ['$limit' => 10],
]);

foreach ($results as $doc) {
    echo $doc->_id;    // category name
    echo $doc->total;  // aggregated sum
}

// mongodb/mongodb's type-safe builder
use MongoDB\Builder\Stage;
use MongoDB\Builder\Accumulator;

$results = $orders->aggregate(
    Stage::match(status: 'completed')
        ->lookup(from: 'customers', localField: 'customer_id', foreignField: '_id', as: 'customer')
        ->unwind('$customer')
        ->group(
            _id: '$customer_id',
            totalSpent: Accumulator::sum('$amount'),
            orderCount: Accumulator::count(),
            lastOrder: Accumulator::max('$created_at'),
        )
        ->sort(totalSpent: -1)
        ->limit(10)
        ->getPipeline()
);

// Single field index
$users->createIndex(['email' => 1]);                           // 'email_1'

// Compound index
$users->createIndex(['status' => 1, 'created_at' => -1]);     // 'status_1_created_at_-1'

// Unique index
$users->createIndex(['email' => 1], ['unique' => true]);

// Named index
$users->createIndex(['email' => 1], ['name' => 'custom_idx']); // 'custom_idx'

// Text index
$users->createIndex(['content' => 'text']);

// TTL index (auto-expire documents)
$users->createIndex(['expires_at' => 1], ['expireAfterSeconds' => 3600]);

// Sparse index
$users->createIndex(['optional_field' => 1], ['sparse' => true]);

// Multiple indexes at once
$names = $users->createIndexes([
    ['key' => ['name' => 1]],
    ['key' => ['age' => -1]],
    ['key' => ['status' => 1, 'name' => 1]],
]);
// ['name_1', 'age_-1', 'status_1_name_1']

// List all indexes
$indexes = $users->listIndexes();

// Drop indexes
$users->dropIndex('email_1');
$users->dropIndexes(); // drops all except _id

// Explain find
$plan = $users->explain(['status' => 'active']);
$plan = $users->explain(); // empty filter

// Via builder
$plan = $users->find()
    ->filter(['status' => 'active'])
    ->sort(['created_at' => -1])
    ->explain();

// Explain aggregation
$plan = $users->explainAggregate([
    ['$match' => ['status' => 'completed']],
    ['$group' => ['_id' => '$category', 'total' => ['$sum' => '$amount']]],
]);

$stream = $users->watch(
    [['$match' => ['operationType' => 'insert']]],  // pipeline filter
    ['maxAwaitTimeMS' => 1000],                       // options
);

foreach ($stream as $event) {
    echo $event->operationType;
    echo $event->fullDocument->name;
}

$doc = $users->findOne(['email' => '[email protected]']);

// Property access (with type conversion)
$doc->name;                          // 'Omar'
$doc->age;                           // 30
$doc->active;                        // true
$doc->missing;                       // null (missing fields return null)

// Nested documents become Document instances
$doc->address->city;                 // 'Amman'
$doc->address->geo->lat;             // 31.95

// Arrays stay as arrays
$doc->tags;                          // ['php', 'mongodb']
$doc->scores;                        // [95, 87, 92]

// Dates become DateTimeImmutable
$doc->created_at;                    // DateTimeImmutable
$doc->created_at->format('Y-m-d');   // '2026-04-04'

// ObjectId
$doc->id();                          // ObjectId instance
echo $doc->_id;                      // '507f...' via __toString

// Existence checks
$doc->has('email');                   // true
$doc->has('missing');                 // false
isset($doc->email);                  // true

// Default values
$doc->get('role', 'user');           // 'user' if role is missing
$doc->get('name', 'Anonymous');      // 'Omar' (field exists)

// Plain PHP array — no Document objects, no BSON types
$array = $doc->toArray();
$array['address']['city']; // 'Amman' (plain array, not Document)
$array['_id'];             // '507f...' (string, not ObjectId)

// JSON string
$json = $doc->toJson();
$json = $doc->toJson(JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

// Raw data — no conversion, original BSON types preserved
$raw = $doc->getRaw();
$raw['_id']; // ObjectId instance

// ArrayAccess (read-only)
$doc['name'];           // 'Omar'
isset($doc['name']);    // true
$doc['name'] = 'x';    // throws LogicException ('Document is immutable')
unset($doc['name']);    // throws LogicException

// JsonSerializable
json_encode($doc);      // '{"_id":"507f...","name":"Omar",...}'

$cursor = $users->find()->filter(['status' => 'active'])->execute();

// Iterate
foreach ($cursor as $index => $doc) {
    echo "$index: {$doc->name}";
}

// Collect all
$docs = $cursor->toArray();     // list<Document>

// First document
$first = $cursor->first();     // Document|null

// Lazy generator
$gen = $cursor->lazy();
foreach ($gen as $doc) { ... }

// Count (consumes the cursor)
$count = $cursor->count();     // int

use PHPdot\MongoDB\Filter\Filter;

$filter = Filter::new()
    ->eq('status', 'active')
    ->gte('age', 18)
    ->toArray();
// ['status' => 'active', 'age' => ['$gte' => 18]]

$users->find()->where(fn(Filter $f) => $f->eq('status', 'active')->gte('age', 18))->execute();
$users->updateOne()->where(fn(Filter $f) => $f->eq('name', 'Omar'))->update([...])->execute();
$users->deleteMany()->where(fn(Filter $f) => $f->lt('expires_at', $now))->execute();

$f->eq('status', 'active');     // status = 'active'
$f->ne('status', 'deleted');    // status != 'deleted'
$f->gt('age', 18);              // age > 18
$f->gte('age', 18);             // age >= 18
$f->lt('age', 65);              // age < 65
$f->lte('age', 65);             // age <= 65

// Range — operators stack on the same field
$f->gte('age', 18)->lte('age', 65);
// ['age' => ['$gte' => 18, '$lte' => 65]]

$f->in('status', ['active', 'pending']);          // status in [...]
$f->nin('role', ['banned', 'suspended']);          // status not in [...]
$f->all('tags', ['php', 'mongodb']);               // array contains all
$f->size('tags', 3);                               // array has exactly 3 elements
$f->elemMatch('scores', ['$gte' => 80, '$lt' => 100]); // array element matches

$f->or(
    Filter::new()->eq('role', 'admin'),
    Filter::new()->gt('score', 90),
);

$f->and(
    Filter::new()->eq('status', 'active'),
    Filter::new()->gte('age', 18),
);

$f->nor(
    Filter::new()->eq('status', 'banned'),
    Filter::new()->eq('role', 'bot'),
);

$f->not('age', ['$gt' => 100]);

$f->exists('email');              // field exists
$f->exists('deletedAt', false);   // field does not exist
$f->type('age', 'int');           // field is of BSON type

$f->regex('name', '^Omar', 'i');  // regex with flags
$f->regex('email', '@example\.com$');

$f->text('mongodb php');          // full-text search (

$f->near('location', [35.9, 31.9], maxDistance: 1000.0);
$f->near('location', [35.9, 31.9], maxDistance: 5000.0, minDistance: 100.0);

$f->raw(['$where' => 'this.age > 18']);
$f->raw(['age' => ['$mod' => [5, 0]]]);

use PHPdot\MongoDB\Logging\QueryLogger;

$logger = new QueryLogger(
    maxEntries: 100,        // ring buffer size (overwrites oldest when full)
    slowThresholdMs: 50.0,  // threshold for slow query flag
);

$db = new Database($connection, $logger);

// Use normally — all operations are logged
$db->collection('users')->findOne(['status' => 'active']);
$db->collection('users')->insertOne(['name' => 'Test']);

// Query the log
$logger->getAll();            // list<QueryLog>
$logger->getSlow();           // list<QueryLog> (only slow queries)
$logger->count();             // int
$logger->getSlowThreshold();  // float
$logger->clear();             // reset

// Each entry (readonly)
foreach ($logger->getAll() as $log) {
    $log->operation;   // 'findOne', 'insertOne', 'aggregate', etc.
    $log->collection;  // 'users'
    $log->filter;      // ['status' => 'active']
    $log->durationMs;  // 2.34
    $log->slow;        // false
}

use PHPdot\MongoDB\GridFS\Bucket;

$bucket = new Bucket($connection);                    // default 'fs' bucket
$bucket = new Bucket($connection, 'uploads');         // custom bucket name
$bucket = new Bucket($connection, 'uploads', [        // with options
    'chunkSizeBytes' => 1048576,
]);

// Upload from stream
$source = fopen('/path/to/file.pdf', 'r');
$id = $bucket->uploadFromStream('document.pdf', $source, [
    'metadata' => ['author' => 'Omar', 'type' => 'invoice'],
]);
fclose($source);

// Download to stream
$dest = fopen('/tmp/download.pdf', 'w');
$bucket->downloadToStream($id, $dest);
fclose($dest);

// Open streams directly
$readStream = $bucket->openDownloadStream($id);
$content = stream_get_contents($readStream);
fclose($readStream);

$writeStream = $bucket->openUploadStream('output.txt');
fwrite($writeStream, 'Hello, GridFS!');
fclose($writeStream);

// Find files
$files = $bucket->find();                               // all files
$files = $bucket->find(['filename' => 'document.pdf']);  // with filter

// Manage
$bucket->rename($id, 'renamed.pdf');
$bucket->delete($id);
$bucket->drop();       // drop entire bucket (files + chunks)

$bucket->raw();        // MongoDB\GridFS\Bucket escape hatch

use PHPdot\MongoDB\Exception\DuplicateKeyException;
use PHPdot\MongoDB\Exception\ValidationException;
use PHPdot\MongoDB\Exception\TimeoutException;
use PHPdot\MongoDB\Exception\WriteException;
use PHPdot\MongoDB\Exception\QueryException;
use PHPdot\MongoDB\Exception\ConnectionException;
use PHPdot\MongoDB\Exception\MongoException;

try {
    $users->insertOne(['email' => '[email protected]']);
} catch (DuplicateKeyException $e) {
    // Unique index violation
    $e->getCollection();   // 'users'
    $e->getDuplicateKey(); // 'email_1'
    $e->getCode();         // 11000
    $e->getPrevious();     // original MongoDB\Driver\Exception\RuntimeException
} catch (ValidationException $e) {
    // Server-side schema validation failed
    $e->getCollection();   // 'users'
    $e->getCode();         // 121
} catch (TimeoutException $e) {
    // Operation exceeded maxTimeMS
    $e->getOperation();    // 'insertOne'
    $e->getCollection();   // 'users'
} catch (WriteException $e) {
    // Any other write error
    $e->getOperation();
    $e->getCollection();
} catch (QueryException $e) {
    // Read operation error
    $e->getOperation();
    $e->getCollection();
} catch (ConnectionException $e) {
    // MongoConnection lost even after retry
    $e->getHost();
} catch (MongoException $e) {
    // Catch-all for any PHPdot MongoDB exception
}

$users->raw();            // MongoDB\Collection
$db->raw();               // MongoDB\Database
$connection->getClient(); // MongoDB\Client
$bucket->raw();           // MongoDB\GridFS\Bucket

final class FindQuery

filter(array $filter): self
where(callable(Filter): Filter $callback): self
projection(array $fields): self
sort(array $sort): self
limit(int $limit): self
skip(int $skip): self
hint(string|array $hint): self
collation(array $collation): self
maxTimeMS(int $ms): self
batchSize(int $size): self
allowDiskUse(bool $allow = true): self
comment(string $comment): self
session(Session $session): self
option(string $key, mixed $value): self
execute(): Cursor
first(): ?Document
count(): int
explain(): array
getFilter(): array
getOptions(): array

final class UpdateQuery

filter(array $filter): self
where(callable(Filter): Filter $callback): self
update(array $update): self
upsert(bool $upsert = true): self
arrayFilters(array $filters): self
hint(string|array $hint): self
collation(array $collation): self
session(Session $session): self
option(string $key, mixed $value): self
execute(): UpdateResult
getFilter(): array
getUpdate(): array
getOptions(): array

final class DeleteQuery

filter(array $filter): self
where(callable(Filter): Filter $callback): self
hint(string|array $hint): self
collation(array $collation): self
session(Session $session): self
option(string $key, mixed $value): self
execute(): DeleteResult
getFilter(): array
getOptions(): array

final class Bucket

__construct(MongoConnection $connection, string $bucketName = 'fs', array $options = [])
uploadFromStream(string $filename, mixed $source, array $options = []): ObjectId
downloadToStream(ObjectId $id, mixed $destination): void
openDownloadStream(ObjectId $id): mixed (resource)
openUploadStream(string $filename, array $options = []): mixed (resource)
delete(ObjectId $id): void
find(array $filter = [], array $options = []): CursorInterface
rename(ObjectId $id, string $newFilename): void
drop(): void
raw(): GridFSBucket