MongoDB driver examples
Recipes for common tasks against the Nimbus MongoDB endpoint, using stock MongoDB drivers. Each section is independent. Go to the task you need. If you have not connected a driver yet, start with the tutorial.
All examples assume a Nimbus server serving the MongoDB endpoint on
127.0.0.1:27017 (the default) with SCRAM-SHA-256 credentials
app-user / app-secret, as set up in the tutorial.
Build a connection string
Section titled “Build a connection string”The shape Nimbus expects:
mongodb://<username>:<password>@<host>:<port>/<database>- Credentials are your server’s configured SCRAM-SHA-256 username and password, URL-encoded if they contain special characters.
- The database name selects the Nimbus tenant.
If you omit it, you land in the tenant
default. - Nimbus is a single endpoint, not a replica set. Do not pass a
replicaSetoption. With a single host, the driver connects directly. appending?directConnection=trueis harmless but not required.
If your project uses the Nimbus CLI, the @nimbus/mongodb helper package
builds the string for you. Provision it into your project:
nimbus packages provision mongodbThen:
import { mongoUri } from "@nimbus/mongodb";
const uri = mongoUri({ username: "app-user", password: "app-secret", database: "myapp",});// mongodb://app-user:app-secret@127.0.0.1:27017/myapp?directConnection=truemongoUri() defaults to 127.0.0.1, port 27017, and database default,
URL-encodes the credentials, and always appends directConnection=true.
Basic CRUD
Section titled “Basic CRUD”import { MongoClient } from "mongodb";
const client = new MongoClient( "mongodb://app-user:app-secret@127.0.0.1:27017/myapp?directConnection=true",);await client.connect();const tasks = client.db("myapp").collection("tasks");
// Createawait tasks.insertOne({ title: "Write docs", done: false, priority: 2 });await tasks.insertMany([ { title: "Review PR", done: false, priority: 1 }, { title: "Ship release", done: true, priority: 3 },]);
// Read — implicit equality and comparison operatorsconst open = await tasks.find({ done: false }).toArray();const urgent = await tasks.find({ priority: { $lte: 2 } }).toArray();
// Updateawait tasks.updateOne({ title: "Write docs" }, { $set: { done: true } });await tasks.updateMany({ done: true }, { $inc: { priority: -1 } });
// Deleteawait tasks.deleteOne({ title: "Ship release" });
await client.close();Filters support implicit equality plus $eq, $ne, $gt, $gte, $lt,
and $lte. Other filter operators ($in, $or, $regex, $exists, …)
cause Nimbus to return a BadValue error. See
supported operations for the full surface.
Upserts and findAndModify
Section titled “Upserts and findAndModify”// Insert-or-update keyed on a fieldawait tasks.updateOne( { title: "Triage inbox" }, { $set: { done: false }, $setOnInsert: { priority: 5 } }, { upsert: true },);
// Atomically claim a task and get the updated document backconst claimed = await tasks.findOneAndUpdate( { done: false }, { $set: { owner: "ada" } }, { returnDocument: "after" },);Count and distinct
Section titled “Count and distinct”const openCount = await tasks.countDocuments({ done: false });const owners = await tasks.distinct("owner");Aggregate
Section titled “Aggregate”Nimbus supports the pipeline stages $match, $sort, $limit, $skip,
$project, $addFields, $count, $group, and $unwind:
const byOwner = await tasks .aggregate([ { $match: { done: false } }, { $group: { _id: "$owner", open: { $sum: 1 } } }, { $sort: { open: -1 } }, ]) .toArray();Nimbus rejects an unsupported stage and names it in the error. A pipeline never silently degrades.
Use transactions
Section titled “Use transactions”Multi-document transactions work through standard driver sessions. Nimbus
isolates writes inside the transaction until commit. If a concurrent write
conflicts, the commit fails with a WriteConflict error. Your application
decides whether to retry:
const session = client.startSession();try { await session.withTransaction(async () => { const db = client.db("myapp"); await db.collection("accounts").updateOne( { name: "checking" }, { $inc: { balance: -100 } }, { session }, ); await db.collection("accounts").updateOne( { name: "savings" }, { $inc: { balance: 100 } }, { session }, ); });} finally { await session.endSession();}A transaction stays within one database, which maps to one Nimbus tenant. Start separate transactions for separate tenants.
Connect from Python
Section titled “Connect from Python”The same connection string works with pymongo:
from pymongo import MongoClient
client = MongoClient( "mongodb://app-user:app-secret@127.0.0.1:27017/myapp?directConnection=true")tasks = client["myapp"]["tasks"]
tasks.insert_one({"title": "Write docs", "done": False})for doc in tasks.find({"done": False}): print(doc)Connect from Go
Section titled “Connect from Go”With the official Go driver:
package main
import ( "context" "fmt"
"go.mongodb.org/mongo-driver/v2/bson" "go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/v2/mongo/options")
func main() { uri := "mongodb://app-user:app-secret@127.0.0.1:27017/myapp?directConnection=true" client, err := mongo.Connect(options.Client().ApplyURI(uri)) if err != nil { panic(err) } defer client.Disconnect(context.Background())
tasks := client.Database("myapp").Collection("tasks") if _, err := tasks.InsertOne(context.Background(), bson.M{"title": "Write docs", "done": false}); err != nil { panic(err) }
cur, err := tasks.Find(context.Background(), bson.M{"done": false}) if err != nil { panic(err) } var results []bson.M if err := cur.All(context.Background(), &results); err != nil { panic(err) } fmt.Println(results)}Work with multiple tenants
Section titled “Work with multiple tenants”Each database name is its own isolated Nimbus tenant. One client can address several:
const acme = client.db("acme").collection("orders");const globex = client.db("globex").collection("orders");
await acme.insertOne({ sku: "A-1" });// Invisible to globex — different tenant, different storage namespace.const none = await globex.find({ sku: "A-1" }).toArray(); // []Nimbus creates tenants automatically on first access. Database names must be
valid tenant IDs: ASCII letters, digits, _, and -, up to 128 characters.
Change streams are not supported
Section titled “Change streams are not supported”collection.watch() fails: the server rejects $changeStream pipelines
with a CommandNotSupported error rather than emulating a partial feature.
Poll with find where you need to observe changes through the MongoDB
endpoint.
Runnable example apps
Section titled “Runnable example apps”Two complete apps live under
examples/mongodb/
in the source repository. Run them in place from a checkout, against a Nimbus
server serving the MongoDB endpoint:
Node (node).
This script uses the stock mongodb driver and the @nimbus/mongodb URI
helper. It runs create, read, update, and read-again operations on a messages
collection.
Tasks.
This app implements the shared
tasks
task list. It creates, lists, toggles, and deletes records in a tasks
collection. The app sorts tasks newest-first by createdAt. Change streams
are unavailable on this surface, so the live-update flow uses polling. The
example reads the list until a change appears. It does not emulate a
subscription.
Both apps set NIMBUS_MONGODB_USERNAME and NIMBUS_MONGODB_PASSWORD. The host
and port default to 127.0.0.1:27017. See each README for the exact run
command.
Related pages
Section titled “Related pages”- Supported operations: the exact command, filter, update, and aggregation surface.
- Supported drivers: driver and tool compatibility.
- Tenant isolation: how database names map to tenants.