← 连接 MongoDB createCollection 创建集合 →

Node.js创建MongoDB数据库教程:连接URL与自动建库机制

著
原创 2026-10-14 Node.js 已有人查阅

一、MongoDB建库逻辑与关系型数据库的差别

在MySQL中建一个库,需要显式执行CREATEDATABASEdbname。MongoDB没有对应的独立命令,数据库的创建是隐式的:当Node.js应用通过MongoClient连接一个不存在的数据库名,并且对该库执行写操作时,MongoDB才会真正创建它。

这里有一个容易被误解的点。连接URL中写了数据库名,并不等于数据库立刻出现在磁盘上。MongoClient.connect成功只代表客户端与服务端建立了连接,数据库本身仍处于“惰性创建”状态。真正让数据库落盘的动作,是向该库的某个插入第一条文档。理解这个机制,可以避免在调试时反复确认“库建了没有”却看到列表为空的情况。

二、连接URL的组成与数据库名的位置

以教程中给出的URL为例:

mongodb://localhost:27017/MongoDatabase

它由四部分组成。mongodb://是协议前缀,标识使用MongoDB连接字符串格式。localhost是主机地址,27017是MongoDB默认监听端口。之后的MongoDatabase就是目标数据库名。

数据库名在这一段字符串中承担了双重角色:它既是客户端连接的默认库,也是后续db.collection(...)操作的上下文。如果省略数据库名,只写mongodb://localhost:27017,那么连接本身仍然建立,但后续调用client.db()时必须显式传入库名,否则无法确定操作目标。

在项目实践中,更常见的写法是把连接地址放在环境变量里,而不是硬编码在代码中。原因很直接:开发、测试、生产环境的地址不同,硬编码会导致每次部署都要改源码。可以把mongodb://127.0.0.1:27017/MongoDatabase写入.env文件,代码中通过process.env.MONGO_URI读取。

连接本地服务时把localhost换成127.0.0.1可以规避Node.js18之后DNS解析优先走IPv6的问题。这一点在上一节已经说明,此处不再展开,但它是本地连接失败的常见原因之一。

三、项目目录组织与createdatabase.js示例

教程建议在桌面创建MongoDatabase文件夹,并在其中放置createdatabase.js。从工程角度看,把数据库名同时用作项目文件夹名并不是必须的,但保持命名一致有助于在多个项目之间快速定位。以下用代码号学习编程的命名风格给出一个结构清晰的示例。

先建目录并初始化:

mkdir codehao-mongodb
cd codehao-mongodb
npm init -y
npm install mongodb --save

然后创建createdatabase.js:

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

const url = 'mongodb://127.0.0.1:27017/codehao_learning';

async function createDatabase() {
  const client = new MongoClient(url);
  try {
    await client.connect();
    console.log('数据库连接成功');

    const db = client.db('codehao_learning');
    const collection = db.collection('students');

    const result = await collection.insertOne({
      name: '代码号学员',
      course: 'Node.js 与 MongoDB',
      createdAt: new Date()
    });

    console.log('数据库已创建,插入文档 _id:', result.insertedId);
  } catch (err) {
    console.error('操作失败:', err.message);
    throw err;
  } finally {
    await client.close();
  }
}

createDatabase();

这段代码与教程原例的区别在于三点。第一,使用了async/await而不是回调函数,这是当前Node.js的主流写法,异常处理也更清晰。第二,不只是连接,还执行了一次insertOne,这样数据库才会真正创建,而不是停留在“连接成功”的状态。第三,finally块中调用client.close(),保证无论成功还是失败都释放连接。

运行方式:

node createdatabase.js

控制台会依次输出连接成功、插入文档的_id。此时用mongosh连上去执行showdbs,就能在列表中看到codehao_learning。

四、为什么只连接不写入时数据库不出现

很多人第一次按教程操作时会遇到这种情况:console.log("Databasecreated!")打印了,但showdbs里找不到这个库。这不是代码写错了,而是MongoDB的惰性创建机制在起作用。

数据库和都是在第一次写入数据时创建的。只建立连接、不做任何写操作,MongoDB不会在磁盘上为这个库分配空间。这个设计减少了空库的元数据开销,但也意味着调试时需要额外一步验证。

验证的方式有三种。用mongosh执行showdbs;用Node.js执行db.listCollections().toArray();或者直接插入一条文档,然后再次查询数据库列表。第三种方式最直接,也最贴近实际项目中的用法,因为项目最终总是要写数据的。

五、项目实例:课程报名记录的建库流程

把上面的逻辑扩展成一个更接近实际业务的场景。假设代码号学习编程平台需要记录学员的报名信息,数据库名为codehao_enrollment,为enrollments。

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

const uri = process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/codehao_enrollment';

async function initEnrollment() {
  const client = new MongoClient(uri, {
    serverSelectionTimeoutMS: 5000
  });

  try {
    await client.connect();
    const db = client.db('codehao_enrollment');
    const enrollments = db.collection('enrollments');

    await enrollments.createIndex({ studentId: 1, courseId: 1 }, { unique: true });

    await enrollments.updateOne(
      { studentId: 'stu2026', courseId: 'node-mongodb' },
      {
        $set: { updatedAt: new Date() },
        $setOnInsert: { enrolledAt: new Date(), status: 'active' }
      },
      { upsert: true }
    );

    const count = await enrollments.countDocuments();
    console.log('当前报名记录数:', count);
  } catch (err) {
    console.error('初始化失败:', err.message);
  } finally {
    await client.close();
  }
}

initEnrollment();

这里的serverSelectionTimeoutMS设成5000毫秒,是为了在服务端不可达时更快失败,而不是用默认的较长时间等待。createIndex在第一次被写入时一并触发建库与建。upsert:true让重复运行这段脚本不会产生重复记录,这在初始化脚本中比先查后写更稳妥。

六、错误处理与连接关闭

教程原例中用if(err)throwerr;处理错误。这种写法在简单示例中能跑通,但在项目中不够。抛出的错误如果没有被上层捕获,会导致进程退出,而连接可能没有被关闭,测试环境下会留下悬挂句柄。

更合理的做法是把连接和操作放在同一个try块中,在catch中记录错误并决定是否重试,在finally中关闭连接。如果使用Express或Fastify,可以把client.close()挂到进程信号上:

process.on('SIGINT', async () => {
  await client.close();
  process.exit(0);
});

另一个容易忽略的点是,MongoClient.connect()在服务端未启动时会抛错,但错误信息有时只显示ECONNREFUSED,不包含具体地址。调试时先把连接地址打印出来,确认端口和IP是否写对,比反复改代码更有效。

七、关于权限认证的补充

上面所有示例都假设本地MongoDB没有开启认证。生产环境中需要创建用户并启用auth。连接URL的格式会变成:

mongodb://username:password@host:27017/dbname?authSource=admin

authSource指定认证数据库,通常是admin。如果这一步配置错误,即使用户名密码正确,也会收到认证失败。项目部署到服务器时,先在mongosh中用同样的凭据手动连接一次,可以排除URL拼接错误。

本节课程知识要点

  • MongoDB没有独立的建库命令,数据库在第一次写入数据时自动创建。

  • 连接URL中的数据库名既是默认操作库,也是后续client.db()的上下文。

  • 只连接不写入时,showdbs看不到该库,这是惰性创建机制的正常表现。

  • 用async/await替代回调写法,finally中关闭连接,避免悬挂句柄。

  • 连接地址优先用127.0.0.1,生产环境把URI放入环境变量。

  • 初始化脚本中用upsert配合唯一索引,可以重复执行而不产生脏数据。

  • 生产环境需要配置认证,authSource是常见出错点。

练习思考题

写一个脚本,连接mongodb://127.0.0.1:27017/codehao_practice,向logs插入一条包含action、timestamp字段的文档,然后查询该的文档总数并打印。尝试在插入之前先执行一次db.listCollections().toArray(),观察输出结果,解释为什么此时列表为空。

← 连接 MongoDB createCollection 创建集合 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号