easy-pingv0.7.0

Get in touch

Questions, bug reports, or anything about easy-ping. Either of these reaches me.

Emailteklumo.jembere@gmail.comTelegram@teklumt

For anything others would benefit from, a GitHub issue is better than a DM, because it's searchable.

GitHub

Adapters / MongoDB

Edit this page

MongoDB

The same library, the same conformance suite, no tables — just indexes.

Setup

notify.ts
import { MongoClient } from "mongodb";
import { createMongoIndexes, mongoAdapter } from "easy-ping/adapters/mongodb";

const client = new MongoClient(process.env.MONGO_URL!);
await client.connect();
const db = client.db("app");

await createMongoIndexes(db);  // once at startup

export const notify = easyPing({
  database: mongoAdapter(db, { client }),  // pass the client, not just the db
  // ...
});

Everything above the database line is identical to the Postgres path — same config shape, same send(), same routes, same client. The adapter boundary is the only thing that changes.

Pass the client

{ client } is what makes createNotifications atomic — a notification and its deliveries land in one transaction, or neither does. Omit it and the adapter still works; it just stops guaranteeing that a crash between the two writes can't leave a notification with no deliveries.

Why it needs a replica set

MongoDB only offers transactions on a replica set — a standalone mongod rejects a session outright. A single-node replica set is enough for local development:

docker-compose.yml
mongo:
  image: mongo:7
  command: ["mongod", "--replSet", "rs0", "--bind_ip_all"]
  ports: ["27017:27017"]
  healthcheck:
    test: mongosh --quiet --eval "try { rs.status().ok } catch (e) { rs.initiate().ok }"
    interval: 2s
    retries: 30

Indexes instead of migrations

There are no tables on MongoDB, so there's nothing to migrate in the SQL sense — createMongoIndexes(db) is both the setup step and the upgrade step, because createIndex is idempotent: rerunning it after a version bump adds whatever's new and leaves existing indexes alone. See Upgrading for how this compares to the Postgres path.

One index is worth knowing about specifically: the dedupe index is a partial unique index (partialFilterExpression: { dedupeKey: { $type: "string" } }), because a plain unique index treats every missing dedupeKey as the same null and would allow exactly one undeduped notification per user — the opposite of what Postgres does with NULL. The partial filter is what makes the two databases agree on dedupe semantics.

Change-stream wake-ups

The replica set you already run for transactions also gives you change streams, which is what mongoSignals uses to wake other replicas' workers and event streams when this one commits a send:

import { mongoAdapter, mongoSignals } from "easy-ping/adapters/mongodb";

export const notify = easyPing({
  database: mongoAdapter(db, { client }),
  signals: mongoSignals(db),   // { collection?: "easy_ping_signals", size?: 1 MiB, onError? }
  // ...
});

Signals are inserts into a small capped collection that the process creates on first use and watches for inserts. Old signals fall off the end; nobody reads history. Each process tags its own inserts so it does not react to its own echo.