Connections

你可以使用 mongoose.connect() 方法连接 MongoDB 。

mongoose.connect('mongodb://localhost/myapp');

这是连接到本地 myapp 数据库默认接口(27017)的最小配置。 本地连接失败可以尝试连接 127.0.0.1 。 local hostname 被修改有时候会引起问题。

你也可以在 uri 中指定多个参数:

mongoose.connect('mongodb://username:password@host:port/database?options...');

详情请看 mongodb connection string spec for more detail.

操作缓存

你不必等待连接建立成功就可以使用你的 Mongoose models 。

mongoose.connect('mongodb://localhost/myapp');
var MyModel = mongoose.model('Test', new Schema({ name: String }));
// 可行
MyModel.findOne(function(error, result) { /* ... */ });

Mongoose 会缓存你的 model 操作。这个操作很方便,但也回引起一些疑惑, 因为如果你没连上 ,Mongoose 不会 抛错。

var MyModel = mongoose.model('Test', new Schema({ name: String }));
// 连接成功前操作会被挂起
MyModel.findOne(function(error, result) { /* ... */ });

setTimeout(function() {
  mongoose.connect('mongodb://localhost/myapp');
}, 60000);

要禁用缓存,请修改 bufferCommands 配置。 如果你打开了 bufferCommands 连接被挂起,尝试关闭 bufferCommands 检查你是否正确打开连接。 你也可以全局禁用 bufferCommands

mongoose.set('bufferCommands', false);

选项

connect 方法也接受 options 参数,这些参数会传入底层 MongoDB 驱动。

mongoose.connect(uri, options);

完整参数列表请参考 MongoDB Node.js 驱动文档 connect()。 Mongoose 会不做修改直接把选项传到驱动,以下有一点例外

  • bufferCommands - 这是 mongoose 特有的选项 (不传到 MongoDB) ,禁用 mongoose 缓存机制
  • user/pass - 用于认证的用户名和密码。mongoose 特有,等价于 MongoDB 驱动的 auth.userauth.password 选项
  • autoIndex - 默认情况下,mongoose 在连接时会自动建立 schema 的索引。这有利于开发,但是在大型生产环境下不是十分理想,因为索引建立会导致性能下降。如果 autoIndex 设为 false,mongoose 将不会自动建立索引
  • dbName - 指定要连接的数据库名称(覆盖连接字符串)。 如果你使用 mongodb+srv 语法连接 MongoDB Atlas, 你 需要使用 dbName 指定数据库

以下是一些重要选项

  • autoReconnect - 底层 MongoDB 驱动在连接丢失后将自动重连。除非你是可以自己管理连接池的高手,否则不要把这个选项设为 false
  • reconnectTries - If you're connected to a single server or mongos proxy (as opposed to a replica set), the MongoDB driver will try to reconnect every reconnectInterval milliseconds for reconnectTries times, and give up afterward. When the driver gives up, the mongoose connection emits a reconnectFailed event. This option does nothing for replica set connections.
  • reconnectInterval - 见 reconnectTries
  • promiseLibrary - 设定底层 promise 库
  • poolSize - MongoDB 保持的最大 socket 连接数。 poolSize 的默认值是 5。注意,MongoDB 3.4 之前, MongoDB 只允许每个 socket 同时进行一个操作,所以如果你有几个缓慢请求卡着后面快的请求,可以尝试增加连接数。
  • bufferMaxEntries - MongoDB 驱动同样有自己的离线时缓存机制。如果你希望链接错误时终止数据库操作,请将此选项设为 0 以及把 bufferCommands 设为 false

举例:

const options = {
  useMongoClient: true,
  autoIndex: false, // Don't build indexes
  reconnectTries: Number.MAX_VALUE, // Never stop trying to reconnect
  reconnectInterval: 500, // Reconnect every 500ms
  poolSize: 10, // Maintain up to 10 socket connections
  // If not connected, return errors immediately rather than waiting for reconnect
  bufferMaxEntries: 0
};
mongoose.connect(uri, options);

回调

connect() 函数接受回调函数,或返回一个 promise

mongoose.connect(uri, options, function(error) {
  // Check error in initial connection. There is no 2nd param to the callback.
});

// Or using promises
mongoose.connect(uri, options).then(
  () => { /** ready to use. The `mongoose.connect()` promise resolves to undefined. */ },
  err => { /** handle initial connection error */ }
);

连接字符串( Connection String )选项

你也可以在连接字符串填写驱动选项,但是这只适用于 MongoDB 驱动使用的选项, 所以类似 bufferCommands 的 Mongoose 专用选项不能在连接字符串使用。

mongoose.connect('mongodb://localhost:27017/test?connectTimeoutMS=1000&bufferCommands=false');
// The above is equivalent to:
mongoose.connect('mongodb://localhost:27017/test', {
  connectTimeoutMS: 1000
  // Note that mongoose will **not** pull `bufferCommands` from the query string
});

把选项放在连接字符串的劣势是不便于阅读,优势是你只需要写一条连接而不需要把所有设定分开写。 最佳实践是把区分生产环境和开发环境的选项如 socketTimeoutMSconnectTimeoutMS 放在 uri , 把通用的常量如 connectTimeoutMSpoolSize 放在选项对象里。

MongoDB 的文档可以找到关于连接字符串的所有选项。

keepAlive 注意事项

对于长期运行的后台应用,启用毫秒级 keepAlive 是一个精明的操作。不这么做你可能会经常 收到看似毫无原因的 "connection closed" 错误。遇到这个情况, 阅读这篇文章, 你或许会立刻启用 keepAlive:

mongoose.connect(uri, { keepAlive: 120 });

副本集(Replica Set)连接

要连接到副本集,你可以用逗号分隔,传入多个地址。

mongoose.connect('mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]' [, options]);

连接到单节点副本集,需指定 replicaSet 选项。

mongoose.connect('mongodb://host1:port1/?replicaSet=rsName');

多 mongos 支持

使用高性能分片集群,需要连接多个 mongos(MongoDB Shard) 实例。 在 mongoose 5.x 中, 你在连接多个 mongos 时不需要传入任何特殊选项

// Connect to 2 mongos servers
mongoose.connect('mongodb://mongosA:27501,mongosB:27501', cb);

多个连接

之前我们了解如何使用 Mongoose 默认连接方法连接到 MongoDB。但有时候我们需要权限不同的多个连接, 或是连接到不同数据库。这个情况下我们可以使用 mongoose.createConnection(), 它接受之前提到的所有参数,给你返回一个新的连接。

const conn = mongoose.createConnection('mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]', options);

connection 对象后续用于创建和检索 models。 models 的范围总是局限于单个连接。

调用 mongoose.connect() 时,Mongoose 会自动创建默认连接。 你可以使用 mongoose.connection 访问默认连接。

连接池

无论是使用 mongoose.connect 或是 mongoose.createConnection 创建的连接, 都被纳入默认最大为 5 的连接池,可以通过 poolSize 选项调整:

// With object options
mongoose.createConnection(uri, { poolSize: 4 });

const uri = 'mongodb://localhost/test?poolSize=4';
mongoose.createConnection(uri);

v5.x 的变化

从 4.x 升级到 5.x,你可能会看到一下弃用提示, 你不应该在 4.x 使用 useMongoClient 选项:

the server/replset/mongos options are deprecated, all their options are supported at the top level of the options object

旧版的 MongoDB 驱动中你需要为多连接配置特定选项:

mongoose.connect(myUri, {
  server: {
    socketOptions: {
      socketTimeoutMS: 0,
      keepAlive: true
    },
    reconnectTries: 30
  },
  replset: {
    socketOptions: {
      socketTimeoutMS: 0,
      keepAlive: true
    },
    reconnectTries: 30
  },
  mongos: {
    socketOptions: {
      socketTimeoutMS: 0,
      keepAlive: true
    },
    reconnectTries: 30
  }
});

mongoose v5.x 中,你可以把所有选项写在顶层而不用嵌套到每个属性。 点击这里查看所有选项列表

// Equivalent to the above code
mongoose.connect(myUri, {
  socketTimeoutMS: 0,
  keepAlive: true,
  reconnectTries: 30
});

下一步

现在我们介绍了 mongoose 的连接方式,接着看看 models