Node.js: MongoDB with Node.js

Last updated: 2026-08-26

1. Why Choose MongoDB

Alice’s e-commerce API faces a tricky problem: product attributes vary greatly across different categories—laptops have CPU and memory fields, clothing has size and color fields, and food has expiration date fields. If a relational database were used, the table structure would have to be modified every time a new category was added. MongoDB’s document model naturally supports records with different structures; each product document can have completely different fields without requiring any schema migration.

SQL Concepts MongoDB Concepts Description
Database Database Database, consistent terminology
Table Collection Table → Collection
Row Document Row → Document
Column Field Column → Field
Primary Key _id (ObjectId) Primary key auto-generated
JOIN $lookup (Aggregation) Different types of join queries
Schema No Enforced Schema Optional Validation Rule
Index Index Similar indexing mechanisms


2. Installation and Connection

(1) Install the MongoDB driver

Use the official mongodb npm package to connect to a MongoDB server.

▶ Example: Installing a Driver

BASH
npm install mongodb

(2) Establish a client connection

MongoClient is the entry point for connecting to MongoDB; it specifies the address and options via a connection string.

▶ Example: Basic Connection

JAVASCRIPT
const { MongoClient } = require('mongodb');

const uri = 'mongodb://localhost:27017';
const client = new MongoClient(uri);

async function connect() {
  try {
    await client.connect();
    console.log('Connected to MongoDB');
    const db = client.db('myapp');
    return db;
  } catch (err) {
    console.error('Connection failed:', err.message);
    process.exit(1);
  }
}
▶ Try it Yourself

(3) Connection Pools and Configuration Options

MongoClient Built-in connection pool; the pool size and behavior are controlled via options.

▶ Example: Connection with Connection Pool Configuration

JAVASCRIPT
const client = new MongoClient(uri, {
  maxPoolSize: 10,
  minPoolSize: 2,
  maxIdleTimeMS: 30000,
  serverSelectionTimeoutMS: 5000,
  connectTimeoutMS: 10000,
});
▶ Try it Yourself
Configuration Option Default Value Description
maxPoolSize 100 Maximum number of connections in the connection pool
minPoolSize 0 Minimum number of connections in the connection pool
maxIdleTimeMS 0 Idle connection timeout (0 = no timeout)
serverSelectionTimeoutMS 30000 Server selection timed out
connectTimeoutMS 30000 Connection establishment timed out
socketTimeoutMS 0 Socket timeout
retryWrites true Automatically retry write operations

(4) Gracefully Closing Connections

When the application exits, it must close connections and release resources.

▶ Example: Graceful Shutdown

JAVASCRIPT
process.on('SIGINT', async () => {
  await client.close();
  console.log('MongoDB connection closed');
  process.exit(0);
});
▶ Try it Yourself

3. CRUD Operations

(1) Insert a document

Use insertOne to insert a single document, and insertMany to insert multiple documents.

▶ Example: Inserting Product Documentation

JAVASCRIPT
const products = db.collection('products');

const result = await products.insertOne({
  name: 'Mechanical Keyboard',
  price: 89.99,
  category: 'electronics',
  specs: { switches: 'Cherry MX Blue', layout: 'ANSI' },
  createdAt: new Date(),
});

console.log('Inserted ID:', result.insertedId);
▶ Try it Yourself

(2) Search the documentation

find Returns the cursor; findOne returns a single document.

▶ Example: Querying Products

JAVASCRIPT
const product = await products.findOne({ category: 'electronics' });
console.log(product);

const cursor = products.find({ price: { $gt: 50 } });
const expensive = await cursor.toArray();
console.log(`${expensive.length} products found`);
▶ Try it Yourself

(3) Update the documentation

updateOne Updates the first match; updateMany updates all matches.

▶ Example: Updating Product Prices

JAVASCRIPT
const updateResult = await products.updateOne(
  { name: 'Mechanical Keyboard' },
  { $set: { price: 79.99, updatedAt: new Date() } },
);

console.log('Modified count:', updateResult.modifiedCount);
▶ Try it Yourself

(4) Delete a document

deleteOne Deletes the first match; deleteMany deletes all matches.

▶ Example: Deleting a Product

JAVASCRIPT
const deleteResult = await products.deleteOne({
  name: 'Mechanical Keyboard',
});

console.log('Deleted count:', deleteResult.deletedCount);
▶ Try it Yourself

(5) CRUD Methods Quick Reference

Operation Method Return Value Description
Insert a single record insertOne(doc) {insertedId} Return the automatically generated ID
Insert Multiple insertMany([doc]) {insertedIds, insertedCount} Batch Insert
Query a single record findOne(filter) Document or null Return the first match
Query multiple rows find(filter) Cursor Requires toArray() or iteration
Update a single entry updateOne(filter, update) {modifiedCount} Update only the first entry
Update multiple entries updateMany(filter, update) {modifiedCount} Update all matches
Delete a single entry deleteOne(filter) {deletedCount} Delete the first match
Delete Multiple deleteMany(filter) {deletedCount} Delete All Matches
Replace in Document replaceOne(filter, doc) {modifiedCount} Replace in Entire Document


4. ObjectId and Query Operators

(1) The ObjectId Mechanism

The default _id for each document is of type ObjectId; the 12-byte encoding includes a timestamp, machine identifier, and counter.

▶ Example: Using ObjectId

JAVASCRIPT
const { ObjectId } = require('mongodb');

const id = new ObjectId();
console.log('ID string:', id.toHexString());
console.log('Timestamp:', id.getTimestamp());

const product = await products.findOne({
  _id: new ObjectId('6850a1b2c3d4e5f6a7b8c9d0'),
});
▶ Try it Yourself

(2) Comparison Operators

▶ Example: Comparison Query

JAVASCRIPT
const expensive = await products.find({ price: { $gt: 100 } }).toArray();
const cheap = await products.find({ price: { $lt: 20 } }).toArray();
const midRange = await products.find({ price: { $gte: 50, $lte: 100 } }).toArray();
▶ Try it Yourself

(3) Logical and Set Operators

▶ Example: $in and $or queries

JAVASCRIPT
const selected = await products.find({
  category: { $in: ['electronics', 'books'] },
}).toArray();

const mixed = await products.find({
  $or: [
    { price: { $lt: 10 } },
    { category: 'electronics' },
  ],
}).toArray();
▶ Try it Yourself

(4) Regular Expression Queries

▶ Example: Regular expression matching product names

JAVASCRIPT
const matched = await products.find({
  name: { $regex: /^Mechanical/i },
}).toArray();
▶ Try it Yourself

(5) Quick Reference for Query Operators

Operator Syntax Description
$eq {field: {$eq: val}} equals (and {field: val})
$gt {field: {$gt: val}} Greater than
$gte {field: {$gte: val}} Greater than or equal to
$lt {field: {$lt: val}} less than
$lte {field: {$lte: val}} Less than or equal to
$ne {field: {$ne: val}} Not equal to
$in {field: {$in: [v1,v2]}} Within the array
$nin {field: {$nin: [v1,v2]}} Not in the array
$or {$or: [{...},{...}]} or condition
$and {$and: [{...},{...}]} Conditions
$not {field: {$not: {...}}} Unselect
$regex {field: {$regex: 'pattern'}} Regular expression match
$exists {field: {$exists: true}} Does the field exist?


5. Projection and Sorting

(1) Projection Control Return Field

Projection specifies which fields to return or exclude, thereby reducing network traffic.

▶ Example: Projection Query

JAVASCRIPT
const names = await products.find(
  {},
  { projection: { name: 1, price: 1, _id: 0 } },
).toArray();

const withoutSpecs = await products.find(
  {},
  { projection: { specs: 0, createdAt: 0 } },
).toArray();
▶ Try it Yourself

(2) Sorting and Pagination

sort sorts the results, while skip and limit implement pagination.

▶ Example: Sorting and Pagination

JAVASCRIPT
const page = 2;
const pageSize = 10;

const sorted = await products.find({})
  .sort({ price: -1, name: 1 })
  .skip((page - 1) * pageSize)
  .limit(pageSize)
  .toArray();
▶ Try it Yourself

6. Index Basics

(1) Create an index

Indexes speed up queries but increase write overhead and storage space.

▶ Example: Creating an Index

JAVASCRIPT
await products.createIndex({ name: 1 });
await products.createIndex({ category: 1, price: -1 });
await products.createIndex({ name: 'text' });

const indexes = await products.indexes();
console.log(indexes);
▶ Try it Yourself

(2) Unique Indexes and Composite Indexes

▶ Example: Unique Index

JAVASCRIPT
await products.createIndex({ sku: 1 }, { unique: true });
▶ Try it Yourself

7. MongoDB Connection and Operation Process

100%
flowchart TD
    A[App Launch] --> B[Create MongoClient]
    B --> C[client.connect]
    C -->|Success| D[Get db Examples]
    C -->|Failure| E[Error Handling/Retry]
    E --> C
    D --> F[Get collection]
    F --> G{CRUD Operation}
    G -->|Write| H[insertOne / insertMany]
    G -->|Read| I[find / findOne]
    G -->|Update| J[updateOne / updateMany]
    G -->|Delete| K[deleteOne / deleteMany]
    H --> L[Back insertedId]
    I --> M[Back to the Document/Cursor]
    J --> N[Back modifiedCount]
    K --> O[Back deletedCount]
    L --> P{Continue?}
    M --> P
    N --> P
    O --> P
    P -->|Yes| G
    P -->|No| Q[client.close]
    Q --> R[Exit the app]


8. Comprehensive Example: Product Management Data Access Layer

JAVASCRIPT
const { MongoClient, ObjectId } = require('mongodb');

class ProductRepository {
  constructor(uri, dbName) {
    this.client = new MongoClient(uri, {
      maxPoolSize: 10,
      serverSelectionTimeoutMS: 5000,
    });
    this.dbName = dbName;
    this.collection = null;
  }

  async connect() {
    await this.client.connect();
    const db = this.client.db(this.dbName);
    this.collection = db.collection('products');
    await this.collection.createIndex({ name: 1 });
    await this.collection.createIndex({ category: 1, price: -1 });
    console.log('ProductRepository connected');
  }

  async create(productData) {
    const doc = {
      ...productData,
      createdAt: new Date(),
      updatedAt: new Date(),
    };
    const result = await this.collection.insertOne(doc);
    return { ...doc, _id: result.insertedId };
  }

  async findById(id) {
    return await this.collection.findOne({
      _id: new ObjectId(id),
    });
  }

  async findByCategory(category, page = 1, pageSize = 10) {
    const skip = (page - 1) * pageSize;
    const [items, total] = await Promise.all([
      this.collection.find({ category })
        .sort({ price: -1 })
        .skip(skip)
        .limit(pageSize)
        .project({ name: 1, price: 1, category: 1 })
        .toArray(),
      this.collection.countDocuments({ category }),
    ]);
    return { items, total, page, pageSize };
  }

  async update(id, updates) {
    const result = await this.collection.updateOne(
      { _id: new ObjectId(id) },
      { $set: { ...updates, updatedAt: new Date() } },
    );
    return result.modifiedCount > 0;
  }

  async delete(id) {
    const result = await this.collection.deleteOne({
      _id: new ObjectId(id),
    });
    return result.deletedCount > 0;
  }

  async disconnect() {
    await this.client.close();
    console.log('ProductRepository disconnected');
  }
}

async function main() {
  const repo = new ProductRepository(
    'mongodb://localhost:27017',
    'ecommerce',
  );
  try {
    await repo.connect();
    const created = await repo.create({
      name: 'Wireless Mouse',
      price: 29.99,
      category: 'electronics',
      specs: { dpi: 16000, buttons: 6 },
    });
    console.log('Created:', created._id);
    const found = await repo.findById(created._id);
    console.log('Found:', found.name);
    await repo.update(created._id, { price: 24.99 });
    const page = await repo.findByCategory('electronics', 1, 10);
    console.log('Page items:', page.items.length);
    await repo.delete(created._id);
    console.log('Deleted');
  } finally {
    await repo.disconnect();
  }
}

main().catch(console.error);

❓ FAQ

Q Why use MongoDB instead of MySQL?
A When data structures change frequently and fields are not fixed, MongoDB’s document model can adapt without requiring table modifications; if the business involves a large number of transactions and complex relationships, MySQL is more suitable.
Q What is ObjectId?
A ObjectId is a 12-byte unique identifier automatically generated by MongoDB. The first 4 bytes are a timestamp; you can retrieve the creation time using id.getTimestamp() without needing any additional fields.
Q How should the connection pool size be set?
A Generally, set it to 5–10 times the number of CPU cores (maxPoolSize); for I/O-intensive applications, it can be increased appropriately. Set minPoolSize to 2–5 to avoid cold-start delays.
Q How should I handle connection failures?
A Set the serverSelectionTimeoutMS parameter to limit the wait time, log the error in the catch block, and implement graceful degradation; in a production environment, we recommend using a retry mechanism and health checks.
Q What scenarios is MongoDB suitable for?
A It is suitable for scenarios requiring flexible schemas and frequent read/write operations, such as content management, log analysis, IoT data, and product catalogs; it is not suitable for core financial systems that require strong transactional consistency.
Q Can 1s and 0s be mixed in the projection?
A Except for _id, they cannot be mixed—either use all 1s to include the specified fields, or use all 0s to exclude them; _id is returned by default and can be set to 0 individually to exclude it.


9. Exercises

  1. Write a script to connect to a local MongoDB instance and insert 5 product documents of different categories, each containing at least 3 different fields.
  2. Implement a query by price range ($gte/$lte) and sort the results in descending order by price, returning only the "name" and "price" fields
  3. Use the $in and $regex combination to search for products where the category is in the specified list and the name contains a specific keyword
  4. Create composite indexes for frequently queried fields, and use explain() to compare the differences in execution plans before and after indexing.
  5. Create a generic paginated query function that accepts the parameters filter, projection, sort, page, and pageSize

📖 Summary


📝 Exercises

  1. Complete all the code examples in this lesson and make sure each one runs correctly.
  2. Modify the comprehensive example and add your own extensions
  3. Review the official documentation, identify 1–2 APIs not covered in this lesson, and write test code for them.
  4. Reflection: How would you apply what you’ve learned in this lesson to a real-world project?
  5. Try to combine what you’ve learned in this lesson with material from previous lessons to build a small project.
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏