Node Driver and Mongoose (Optional)

Introduction

Node.js talks to MongoDB through the official mongodb driver (low level) or Mongoose (schema, middleware, population). This optional chapter shows both with a small blog API and links to Node database basics without repeating npm fundamentals.

Prerequisites

Install

Official driver:

bash
npm install mongodb

Mongoose (ODM):

bash
npm install mongoose

Official Driver: MongoClient

db.mjs:

Express route:

Code explanation:

  • ObjectId.isValid before constructing ObjectId — avoids exceptions and injection-style bugs — Security
  • Reuse one MongoClient per process (module singleton), not per request

Mongoose: Schema and Model

models/post.js:

Connect once at startup:

javascript
await mongoose.connect(process.env.MONGODB_URI ?? "mongodb://127.0.0.1:27017/hello_demo");

Create and query:

javascript
const post = await Post.create({
  title: "Mongoose Intro",
  slug: "mongoose-intro",
  published: true,
  tags: ["nodejs", "mongodb"],
});
 
const list = await Post.find({ published: true })
  .sort({ createdAt: -1 })
  .limit(20)
  .select("title slug createdAt")
  .lean();

.lean() returns plain objects—faster read-only APIs.

Population (References)

models/comment.js:

javascript
const commentSchema = new mongoose.Schema({
  postId: { type: mongoose.Schema.Types.ObjectId, ref: "Post", required: true },
  author: String,
  body: String,
  createdAt: { type: Date, default: Date.now },
});
 
export const Comment = mongoose.model("Comment", commentSchema);
javascript
const comments = await Comment.find({ postId: post._id })
  .sort({ createdAt: 1 })
  .populate("postId", "title slug");

Population runs extra queries—at scale prefer aggregation $lookupchapter 13.

Middleware Example

javascript
postSchema.pre("save", function (next) {
  if (this.isModified("slug")) {
    this.slug = this.slug.toLowerCase().trim();
  }
  next();
});

Hooks replace some app-layer validation; DB validator still helps — Schema Validation.

Driver vs Mongoose

LayerBest for
mongodb driverFull control, microservices, aggregation-heavy pipelines
MongooseCRUD apps, schema enforcement, hooks, quick REST APIs

Tip

Team choice

Pick Mongoose when the team wants schema docs in code. Pick the native driver when you mirror PyMongo-style dict queries or need minimal abstraction.

FAQ

TypeScript?

Use @types/mongoose or Mongoose 7+ built-in types; driver ships TypeScript definitions.

Next.js API routes?

Connect in a shared module; avoid connecting per request in serverless—use connection pooling patterns or Atlas serverless limits.

Validation vs MongoDB validator?

Mongoose validates before send; MongoDB validator is server-side backup — chapter 14.

Fastify instead of Express?

Same driver/Mongoose—swap HTTP layer only.

Compare Python track?

PyMongo Basics and FastAPI integration cover the same CRUD patterns in Python.