Skip to content

Getting started

DORM brings the ergonomics of the Django ORM to MongoDB in TypeScript: define a model once, then query and write through it — including Django's field__lookup filter syntax, which compiles to MongoDB aggregation pipelines (relational __ traversals become $lookup joins).

Install

bash
npm install @m1abdullah/dorm mongodb

mongodb is a peer dependency (DORM has no other runtime dependencies), so you always control the single copy of the driver.

Requirements. Node.js 20+ and mongodb 6+. DORM is ESM-only (no CommonJS build) — import it with ESM import syntax (or a dynamic import() from CommonJS); a top-level require("@m1abdullah/dorm") is not supported.

Quickstart

ts
import { DORMClient, f } from "@m1abdullah/dorm";

const dorm = new DORMClient(process.env.MONGODB_URL!); // e.g. mongodb://localhost:27017/app

// Declare models synchronously — safe before connecting.
const User = dorm.model(
  "users",
  {
    username: f.string({ required: true }),
    email: f.string({ required: true, unique: true }),
    salary: f.number({ default: 0 }),
    active: f.boolean({ default: true }),
    supervisor: f.ref("users"),
  },
  { timestamps: true },
);

const Asset = dorm.model(
  "assets",
  {
    name: f.string({ required: true }),
    price: f.number({ default: 0 }),
    assigned_to: f.ref("users"),
  },
  { timestamps: true },
);

await dorm.connect();      // open the connection once, at startup
await dorm.ensureIndexes(); // create declared indexes (unique email, …)

// Create — validates, applies defaults + timestamps, returns the stored doc.
const boss = await User.objects.create({ username: "boss", email: "b@co.com", salary: 90000 });
const abed = await User.objects.create({
  username: "abed",
  email: "abed@co.com",
  salary: 40000,
  supervisor: boss._id,
});
await Asset.objects.create({ name: "Macbook", price: 2000, assigned_to: abed._id });

// Query — Django-style lookups.
await User.objects.filter({ salary__gte: 50000 });
await User.objects.get({ username: "abed" });
await User.objects.count({ active: true });

// Relational traversal — assets whose assignee's supervisor earns >= 50k.
await Asset.objects.filter({ assigned_to__supervisor__salary__gte: 50000 });

// Write.
await User.objects.update({ username: "abed" }, { salary: 60000 });
await User.objects.delete({ active: false });

await dorm.close();

Next steps

There's also a runnable Express example in the examples/ folder.

Released under the MIT License.