This tutorial walks you through Rango by building a small example: an app database with a users collection. You connect to PostgreSQL, insert documents, query them with MongoDB-style filters, and update them atomically.
By the end you will know how to open a connection, run the core CRUD operations, and where to go next for advanced features.
Install Rango with Composer:
composer require patchlevel/rangoYou need a running PostgreSQL instance. The fastest way to get one locally is Docker:
docker run --rm -e POSTGRES_PASSWORD=postgres -p 5432:5432 postgres:16-alpineA Client is the entry point. It takes a standard PDO DSN and manages the underlying connection:
use Patchlevel\Rango\Client;
$client = new Client('pgsql:host=localhost;port=5432;dbname=app;user=postgres;password=postgres');You can also pass an existing PDO instance instead of a DSN string. See the connection page for details.
In Rango, a database maps to a PostgreSQL schema and a collection maps to a table. You select them by name, and they are created automatically on the first write:
$collection = $client->selectDatabase('app')->selectCollection('users');You never run migrations by hand. Rango creates the schema and table the first time you write to a collection.
Documents are plain PHP arrays. If you omit the _id, Rango generates one for you:
$collection->insertOne([
'name' => 'John Doe',
'email' => 'john@example.com',
'age' => 27,
'tags' => ['php', 'postgres'],
'profile' => ['stats' => ['score' => 42]],
]);
$result = $collection->insertMany([
['name' => 'Jane Roe', 'email' => 'jane@example.com', 'age' => 31, 'tags' => ['php']],
['name' => 'Max Mustermann', 'email' => 'max@example.com', 'age' => 19, 'tags' => ['mongodb']],
]);
echo $result->getInsertedCount(); // 2Pass a MongoDB-style filter to find. Here you combine an array match with a comparison operator:
$users = $collection->find([
'tags' => 'php',
'age' => ['$gte' => 25],
]);
foreach ($users as $user) {
echo $user['name'] . "\n";
}find returns a Cursor, which you can iterate directly or turn into an array with toArray().
To fetch a single document, use findOne:
$user = $collection->findOne(['email' => 'john@example.com']);Updates use update operators. This increments a nested counter and adds a tag atomically:
$collection->updateOne(
['email' => 'john@example.com'],
[
'$inc' => ['profile.stats.score' => 1],
'$push' => ['tags' => 'mongodb'],
],
);Deleting works the same way, with a filter:
$collection->deleteOne(['email' => 'max@example.com']);You now have a working Rango setup: a client connected to PostgreSQL, a collection that stores documents as JSONB, and the full CRUD cycle running through the MongoDB-style API. Everything you wrote lives in a regular PostgreSQL table you can back up, replicate, and query with SQL.