Node.js 连接 MongoDB(长文解析)

Node.js 连接 MongoDB:从零开始构建数据驱动的应用

在现代 Web 开发中,数据是应用的“血液”。无论是用户登录信息、文章内容,还是订单记录,都需要一个可靠的地方来存储和读取。MongoDB 是目前最受欢迎的 NoSQL 数据库之一,而 Node.js 作为 JavaScript 的服务器端运行环境,天然与 MongoDB 配合得天衣无缝。今天,我们就来手把手教你如何实现 Node.js 连接 MongoDB,让你的应用真正“有血有肉”。

想象一下,你正在搭建一个博客系统。用户写文章,你得把它们存起来,下次打开时又能准确地显示出来。这背后,就是数据库在默默工作。而 Node.js 连接 MongoDB 的过程,就像在为你的应用搭建一座“数据桥梁”——它让代码和数据之间建立起稳定、高效的通信通道。


准备工作:环境与依赖安装

在动手之前,确保你的开发环境已经就绪。你需要:

  • Node.js 14 或更高版本(建议使用 LTS 版本)
  • MongoDB 数据库服务(本地安装或使用云服务如 MongoDB Atlas)
  • 一个代码编辑器(VS Code 推荐)

打开终端,创建一个新项目目录,并初始化项目:

mkdir my-blog-app
cd my-blog-app
npm init -y

接下来,安装核心依赖。我们使用 mongodb 官方驱动,它是连接 MongoDB 的标准方式:

npm install mongodb

✅ 提示:mongodb 包是官方推荐的 Node.js 驱动,支持异步操作,性能优秀,适合生产环境使用。


创建连接:建立数据库通道

现在我们来写第一段关键代码:连接到 MongoDB 服务器。这一步相当于“打开数据库的门”,只有门开了,才能进去存取数据。

新建一个文件 db.js,内容如下:

// db.js
// 导入 MongoDB 官方驱动模块
const { MongoClient } = require('mongodb');

// 数据库连接字符串(请根据实际情况替换)
// 如果是本地运行,通常是 mongodb://127.0.0.1:27017
// 如果是 MongoDB Atlas,格式为:mongodb+srv://<username>:<password>@cluster0.xxx.mongodb.net/
const uri = 'mongodb://127.0.0.1:27017';

// 数据库名称,这里命名为 my_blog_db
const dbName = 'my_blog_db';

// 创建一个全局的数据库连接对象,避免重复连接
let dbClient = null;

// 异步函数:连接 MongoDB 并返回数据库对象
async function connectToDatabase() {
  // 如果已经连接,直接返回
  if (dbClient) return dbClient.db(dbName);

  try {
    // 使用 MongoClient 创建连接
    dbClient = await MongoClient.connect(uri, {
      // 设置连接选项
      // maxPoolSize 控制连接池最大连接数
      maxPoolSize: 10,
      // 连接超时时间(毫秒)
      connectTimeoutMS: 10000,
      // 套接字超时时间
      socketTimeoutMS: 45000,
      // 启用自动重连机制
      retryWrites: true,
      // 使用新格式的连接字符串
      serverSelectionTimeoutMS: 5000
    });

    console.log('✅ 成功连接到 MongoDB!');

    // 返回指定数据库
    return dbClient.db(dbName);

  } catch (error) {
    // 连接失败时输出错误信息
    console.error('❌ 数据库连接失败:', error);
    throw error; // 抛出错误,让调用者处理
  }
}

// 导出连接函数,供其他模块使用
module.exports = { connectToDatabase };

💡 关键点解释:

  • MongoClient.connect() 是异步方法,必须用 async/await.then() 处理。
  • maxPoolSize 控制连接池大小,避免过多连接消耗资源。
  • retryWrites: true 允许写操作在连接失败后自动重试,提升稳定性。
  • connectTimeoutMS 设置连接超时,防止程序卡死。

操作数据库:增删改查(CRUD)实战

连接成功后,我们就可以对数据库执行 CRUD 操作了。接下来,我们以“文章管理”为例,展示如何插入、查询、更新和删除数据。

创建文章集合与初始化数据

在 MongoDB 中,数据以“集合”(Collection)的形式组织,相当于关系型数据库中的“表”。

新建文件 article.js,用于处理文章操作:

// article.js
// 导入数据库连接函数
const { connectToDatabase } = require('./db');

// 定义文章集合名称
const collectionName = 'articles';

// 插入一篇文章
async function insertArticle(title, content, author) {
  const db = await connectToDatabase();
  const collection = db.collection(collectionName);

  // 构造文章对象
  const article = {
    title: title,           // 文章标题
    content: content,       // 文章内容
    author: author,         // 作者
    createdAt: new Date(),  // 创建时间(自动记录)
    tags: ['nodejs', 'mongodb'] // 标签数组
  };

  try {
    // 执行插入操作
    const result = await collection.insertOne(article);
    console.log('✅ 文章插入成功,ID:', result.insertedId);
    return result.insertedId;
  } catch (error) {
    console.error('❌ 插入文章失败:', error);
    throw error;
  }
}

// 查询所有文章
async function getAllArticles() {
  const db = await connectToDatabase();
  const collection = db.collection(collectionName);

  try {
    // 查询所有文档,返回数组
    const articles = await collection.find({}).toArray();
    console.log('📊 查询到', articles.length, '篇文章');
    return articles;
  } catch (error) {
    console.error('❌ 查询文章失败:', error);
    throw error;
  }
}

// 根据标题模糊查询
async function searchArticles(keyword) {
  const db = await connectToDatabase();
  const collection = db.collection(collectionName);

  try {
    // 使用正则表达式进行模糊匹配(不区分大小写)
    const regex = new RegExp(keyword, 'i');
    const results = await collection.find({ title: { $regex: regex } }).toArray();
    console.log('🔍 搜索结果:', results.length, '篇');
    return results;
  } catch (error) {
    console.error('❌ 搜索失败:', error);
    throw error;
  }
}

// 更新文章内容
async function updateArticle(id, newContent) {
  const db = await connectToDatabase();
  const collection = db.collection(collectionName);

  try {
    const result = await collection.updateOne(
      { _id: id }, // 查询条件:根据 ID 查找
      { $set: { content: newContent } } // 更新操作:设置新内容
    );

    if (result.matchedCount === 0) {
      console.log('⚠️ 未找到指定文章');
      return false;
    }

    console.log('✅ 文章更新成功');
    return true;
  } catch (error) {
    console.error('❌ 更新失败:', error);
    throw error;
  }
}

// 删除文章
async function deleteArticle(id) {
  const db = await connectToDatabase();
  const collection = db.collection(collectionName);

  try {
    const result = await collection.deleteOne({ _id: id });
    if (result.deletedCount === 0) {
      console.log('⚠️ 未找到要删除的文章');
      return false;
    }
    console.log('🗑️ 文章删除成功');
    return true;
  } catch (error) {
    console.error('❌ 删除失败:', error);
    throw error;
  }
}

// 导出所有方法
module.exports = {
  insertArticle,
  getAllArticles,
  searchArticles,
  updateArticle,
  deleteArticle
};

验证连接:编写测试脚本

为了让整个流程跑通,我们创建一个测试文件 test.js,用来验证 Node.js 连接 MongoDB 是否成功,以及 CRUD 操作是否正常。

// test.js
// 导入文章操作模块
const { insertArticle, getAllArticles, searchArticles, updateArticle, deleteArticle } = require('./article');

// 测试函数:执行一系列操作
async function runTests() {
  try {
    // 1. 插入一篇文章
    const articleId = await insertArticle(
      'Node.js 与 MongoDB 的完美结合',
      '本文介绍如何使用 Node.js 连接 MongoDB,实现数据持久化...',
      '张三'
    );

    // 2. 查询所有文章
    const allArticles = await getAllArticles();
    console.log('所有文章:', allArticles);

    // 3. 搜索包含“Node.js”的文章
    const searchResults = await searchArticles('Node.js');
    console.log('搜索结果:', searchResults);

    // 4. 更新文章内容
    await updateArticle(articleId, '更新后的内容:Node.js 连接 MongoDB 已经非常成熟,适合中小型项目。');

    // 5. 删除文章
    await deleteArticle(articleId);

    console.log('🎉 所有测试完成!');

  } catch (error) {
    console.error('❌ 测试过程中出错:', error);
  }
}

// 启动测试
runTests();

运行测试脚本:

node test.js

如果看到 ✅ 成功连接到 MongoDB!🎉 所有测试完成!,说明你的 Node.js 连接 MongoDB 已经成功!


高级技巧:连接池与错误处理优化

在实际项目中,连接池管理和错误处理至关重要。我们来补充两个关键点:

1. 使用连接池提升性能

MongoDB 官方驱动默认使用连接池,但你可以通过配置优化:

const client = await MongoClient.connect(uri, {
  maxPoolSize: 20,      // 最大连接数
  minPoolSize: 5,       // 最小连接数
  maxConnecting: 10,    // 最大同时连接数
  connectTimeoutMS: 10000,
  socketTimeoutMS: 45000,
  retryWrites: true
});

📌 小贴士:连接池就像一个“等待区”,多个请求可以复用已建立的连接,避免频繁创建/销毁,提升响应速度。

2. 增强错误处理:优雅降级与日志记录

try {
  const db = await connectToDatabase();
  // 执行操作
} catch (error) {
  console.error('数据库操作失败,尝试重连...', error);
  // 可以加入重试逻辑或返回默认数据
}

总结:从连接到实战

通过本文,你已经掌握了 Node.js 连接 MongoDB 的完整流程:

  • 环境准备与依赖安装
  • 建立稳定、安全的数据库连接
  • 实现完整的 CRUD 操作
  • 编写测试脚本验证功能
  • 了解连接池与错误处理的进阶技巧

这不仅是一次技术实践,更是一次对“数据持久化”本质的理解。当你能自如地在 Node.js 与 MongoDB 之间传递数据时,你就真正拥有了构建全栈应用的能力。

记住,数据库不是“黑箱”,它是你代码的“记忆体”。每一次 insertOnefind,都是在为应用的未来“播种”。

现在,轮到你动手试试了。从一个简单的文章管理系统开始,让数据真正为你所用。