Using MongoDB from Node.js

MongoDB · Practical · 12 min

Applications talk to MongoDB through a driver, and connection handling mistakes are a classic production bug.

Install the driver with npm install mongodb. A MongoClient manages a connection pool; create one per process at startup and reuse it everywhere. Opening a new client per request exhausts connections and adds latency.

client.db("shop").collection("orders") gives you a collection object with the same methods as the shell: insertOne, find, updateMany, aggregate, createIndex... Every operation returns a Promise, so use await. find returns a cursor: call .toArray() for small results or iterate with for await (const doc of cursor) to stream large ones.

Differences from mongosh worth knowing:

  • import types from the package: import { MongoClient, ObjectId } from "mongodb", and convert string ids with new ObjectId(id) before querying _id,
  • numbers in JavaScript are doubles; use Long or Decimal128 when you need exact integers beyond 2^53 or money,
  • results of insertOne etc. are plain objects like { acknowledged, insertedId }.

Keep the connection string (with credentials) in an environment variable, not in code. Call client.close() on shutdown. With TypeScript, db.collection<Order>("orders") types documents. ODMs such as Mongoose add schemas and validation on top of the driver.

Example

import { MongoClient, ObjectId } from "mongodb";

const client = new MongoClient(process.env.MONGODB_URI ?? "mongodb://localhost:27017");
const orders = client.db("shop").collection("orders");   // reuse these everywhere

async function main() {
  const { insertedId } = await orders.insertOne({ customer: "ana", total: 12.5 });
  const doc = await orders.findOne({ _id: new ObjectId(insertedId.toString()) });
  console.log(doc.total);                                  // 12.5

  for await (const o of orders.find({ total: { $gt: 10 } }).sort({ total: -1 })) {
    console.log(o.customer);                               // ana
  }
  const res = await orders.updateMany({ customer: "ana" }, { $set: { vip: true } });
  console.log(res.modifiedCount);                          // 1
}
main().finally(() => client.close());

Remember

  • One MongoClient per process: it is a connection pool
  • Every operation returns a Promise; cursors support for await
  • Convert string ids with new ObjectId(id) before matching _id
  • Keep the URI in an environment variable

Watch out for

  • Creating a new MongoClient for each HTTP request.

Check yourself

  1. A user id arrives in a URL as a 24-character hex string. Why does findOne({ _id: id }) return null?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: www.mongodb.com/docs/drivers/node/current/