/
connections.pug
426 lines (333 loc) · 22.5 KB
/
connections.pug
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
extends layout
append style
link(rel="stylesheet", href="/docs/css/inlinecpc.css")
script(type="text/javascript" src="/docs/js/native.js")
block content
:markdown
<h2><a href="#connections">Connections</a></h2>
<script>
_native.init("CK7DT53U",{
targetClass: 'native-inline'
});
</script>
<div class="native-inline">
<a href="#native_link#"><span class="sponsor">Sponsor</span> #native_company# — #native_desc#</a>
</div>
You can connect to MongoDB with the `mongoose.connect()` method.
```javascript
mongoose.connect('mongodb://localhost:27017/myapp', {useNewUrlParser: true});
```
This is the minimum needed to connect the `myapp` database running locally
on the default port (27017). If connecting fails on your machine, try using
`127.0.0.1` instead of `localhost`.
You can also specify several more parameters in the `uri`:
```javascript
mongoose.connect('mongodb://username:password@host:port/database?options...', {useNewUrlParser: true});
```
See the [mongodb connection string spec](http://docs.mongodb.org/manual/reference/connection-string/) for more detail.
<ul class="toc">
<li><a href="#buffering">Buffering</a></li>
<li><a href="#error-handling">Error Handling</a></li>
<li><a href="#options">Options</a></li>
<li><a href="#connection-string-options">Connection String Options</a></li>
<li><a href="#connection-events">Connection Events</a></li>
<li><a href="#keepAlive">A note about keepAlive</a></li>
<li><a href="#replicaset_connections">Replica Set Connections</a></li>
<li><a href="#replicaset-hostnames">Replica Set Host Names</a></li>
<li><a href="#mongos_connections">Multi-mongos support</a></li>
<li><a href="#multiple_connections">Multiple connections</a></li>
<li><a href="#connection_pools">Connection Pools</a></li>
<li><a href="#v5-changes">Option Changes in v5.x</a></li>
</ul>
<h3 id="buffering"><a href="#buffering">Operation Buffering</a></h3>
Mongoose lets you start using your models immediately, without waiting for
mongoose to establish a connection to MongoDB.
```javascript
mongoose.connect('mongodb://localhost:27017/myapp', {useNewUrlParser: true});
var MyModel = mongoose.model('Test', new Schema({ name: String }));
// Works
MyModel.findOne(function(error, result) { /* ... */ });
```
That's because mongoose buffers model function calls internally. This
buffering is convenient, but also a common source of confusion. Mongoose
will *not* throw any errors by default if you use a model without
connecting.
```javascript
var MyModel = mongoose.model('Test', new Schema({ name: String }));
// Will just hang until mongoose successfully connects
MyModel.findOne(function(error, result) { /* ... */ });
setTimeout(function() {
mongoose.connect('mongodb://localhost:27017/myapp', {useNewUrlParser: true});
}, 60000);
```
To disable buffering, turn off the [`bufferCommands` option on your schema](./guide.html#bufferCommands).
If you have `bufferCommands` on and your connection is hanging, try turning
`bufferCommands` off to see if you haven't opened a connection properly.
You can also disable `bufferCommands` globally:
```javascript
mongoose.set('bufferCommands', false);
```
<h3 id="error-handling"><a href="#error-handling">Error Handling</a></h3>
There are two classes of errors that can occur with a Mongoose connection.
- Error on initial connection. If initial connection fails, Mongoose will **not** attempt to reconnect, it will emit an 'error' event, and the promise `mongoose.connect()` returns will reject.
- Error after initial connection was established. Mongoose will attempt to reconnect, and it will emit an 'error' event.
To handle initial connection errors, you should use `.catch()` or `try/catch` with async/await.
```javascript
mongoose.connect('mongodb://localhost:27017/test', { useNewUrlParser: true }).
catch(error => handleError(error));
// Or:
try {
await mongoose.connect('mongodb://localhost:27017/test', { useNewUrlParser: true });
} catch (error) {
handleError(error);
}
```
To handle errors after initial connection was established, you should
listen for error events on the connection. However, you still need to
handle initial connection errors as shown above.
```javascript
mongoose.connection.on('error', err => {
logError(err);
});
```
<h3 id="options"><a href="#options">Options</a></h3>
The `connect` method also accepts an `options` object which will be passed
on to the underlying MongoDB driver.
```javascript
mongoose.connect(uri, options);
```
A full list of options can be found on the [MongoDB Node.js driver docs for `connect()`](http://mongodb.github.io/node-mongodb-native/2.2/api/MongoClient.html#connect).
Mongoose passes options to the driver without modification, modulo a few
exceptions that are explained below.
* `bufferCommands` - This is a mongoose-specific option (not passed to the MongoDB driver) that disables [mongoose's buffering mechanism](http://mongoosejs.com/docs/faq.html#callback_never_executes)
* `user`/`pass` - The username and password for authentication. These options are mongoose-specific, they are equivalent to the MongoDB driver's `auth.user` and `auth.password` options.
* `autoIndex` - By default, mongoose will automatically build indexes defined in your schema when it connects. This is great for development, but not ideal for large production deployments, because index builds can cause performance degradation. If you set `autoIndex` to false, mongoose will not automatically build indexes for **any** model associated with this connection.
* `dbName` - Specifies which database to connect to and overrides any database specified in the connection string. This is useful if you are unable to specify a default database in the connection string like with [some `mongodb+srv` syntax connections](https://stackoverflow.com/questions/48917591/fail-to-connect-mongoose-to-atlas/48917626#48917626).
Below are some of the options that are important for tuning mongoose.
* `useNewUrlParser` - The underlying MongoDB driver has deprecated their current [connection string](https://docs.mongodb.com/manual/reference/connection-string/) parser. Because this is a major change, they added the `useNewUrlParser` flag to allow users to fall back to the old parser if they find a bug in the new parser. You should set `useNewUrlParser: true` unless that prevents you from connecting. Note that if you specify `useNewUrlParser: true`, you **must** specify a port in your connection string, like `mongodb://localhost:27017/dbname`. The new url parser does _not_ support connection strings that do not have a port, like `mongodb://localhost/dbname`.
* `useCreateIndex` - False by default. Set to `true` to make Mongoose's default index build use `createIndex()` instead of `ensureIndex()` to avoid deprecation warnings from the MongoDB driver.
* `useFindAndModify` - True by default. Set to `false` to make `findOneAndUpdate()` and `findOneAndRemove()` use native `findOneAndUpdate()` rather than `findAndModify()`.
* `autoReconnect` - The underlying MongoDB driver will automatically try to reconnect when it loses connection to MongoDB. Unless you are an extremely advanced user that wants to manage their own connection pool, do **not** set this option to `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` - See `reconnectTries`
* `promiseLibrary` - Sets the [underlying driver's promise library](http://mongodb.github.io/node-mongodb-native/3.1/api/MongoClient.html).
* `poolSize` - The maximum number of sockets the MongoDB driver will keep open for this connection. By default, `poolSize` is 5. Keep in mind that, as of MongoDB 3.4, MongoDB only allows one operation per socket at a time, so you may want to increase this if you find you have a few slow queries that are blocking faster queries from proceeding. See [Slow Trains in MongoDB and Node.js](http://thecodebarbarian.com/slow-trains-in-mongodb-and-nodejs).
* `bufferMaxEntries` - The MongoDB driver also has its own buffering mechanism that kicks in when the driver is disconnected. Set this option to 0 and set `bufferCommands` to `false` on your schemas if you want your database operations to fail immediately when the driver is not connected, as opposed to waiting for reconnection.
* `connectTimeoutMS` - How long the MongoDB driver will wait before killing a socket due to inactivity _during initial connection_. Defaults to 30000. This option is passed transparently to [Node.js' `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback).
* `socketTimeoutMS` - How long the MongoDB driver will wait before killing a socket due to inactivity _after initial connection_. A socket may be inactive because of either no activity or a long-running operation. This is set to `30000` by default, you should set this to 2-3x your longest running operation if you expect some of your database operations to run longer than 20 seconds. This option is passed to [Node.js `socket#setTimeout()` function](https://nodejs.org/api/net.html#net_socket_settimeout_timeout_callback) after the MongoDB driver successfully completes.
* `family` - Whether to connect using IPv4 or IPv6. This option passed to [Node.js' `dns.lookup()`](https://nodejs.org/api/dns.html#dns_dns_lookup_hostname_options_callback) function. If you don't specify this option, the MongoDB driver will try IPv6 first and then IPv4 if IPv6 fails. If your `mongoose.connect(uri)` call takes a long time, try `mongoose.connect(uri, { family: 4 })`
Example:
```javascript
const options = {
useNewUrlParser: true,
useCreateIndex: true,
useFindAndModify: false,
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,
connectTimeoutMS: 10000, // Give up initial connection after 10 seconds
socketTimeoutMS: 45000, // Close sockets after 45 seconds of inactivity
family: 4 // Use IPv4, skip trying IPv6
};
mongoose.connect(uri, options);
```
See [this page](http://mongodb.github.io/node-mongodb-native/3.1/reference/faq/) for more information about `connectTimeoutMS` and `socketTimeoutMS`
<h3 id="callback"><a href="#callback">Callback</a></h3>
The `connect()` function also accepts a callback parameter and returns a
[promise](./promises.html).
```javascript
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 mongoose instance. */ },
err => { /** handle initial connection error */ }
);
```
<h3 id="connection-string-options"><a href="#connection-string-options">Connection String Options</a></h3>
You can also specify driver options in your connection string as
[parameters in the query string](https://en.wikipedia.org/wiki/Query_string)
portion of the URI. This only applies to options passed to the MongoDB
driver. You **can't** set Mongoose-specific options like `bufferCommands`
in the query string.
```javascript
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
});
```
The disadvantage of putting options in the query string is that query
string options are harder to read. The advantage is that you only need a
single configuration option, the URI, rather than separate options for
`socketTimeoutMS`, `connectTimeoutMS`, etc. Best practice is to put options
that likely differ between development and production, like `replicaSet`
or `ssl`, in the connection string, and options that should remain constant,
like `connectTimeoutMS` or `poolSize`, in the options object.
The MongoDB docs have a full list of
[supported connection string options](https://docs.mongodb.com/manual/reference/connection-string/)
<h3 id="connection-events"><a href="#connection-events">Connection Events</a></h3>
Connections inherit from [Node.js' `EventEmitter` class](https://nodejs.org/api/events.html#events_class_eventemitter),
and emit events when something happens to the connection, like losing
connectivity to the MongoDB server. Below is a list of events that a
connection may emit.
* `connecting`: Emitted when Mongoose starts making its initial connection to the MongoDB server
* `connected`: Emitted when Mongoose successfully makes its initial connection to the MongoDB server
* `open`: Equivalent to `connected`
* `disconnecting`: Your app called [`Connection#close()`](api.html#connection_Connection-close) to disconnect from MongoDB
* `disconnected`: Emitted when Mongoose lost connection to the MongoDB server. This event may be due to your code explicitly closing the connection, the database server crashing, or network connectivity issues.
* `close`: Emitted after [`Connection#close()`](api.html#connection_Connection-close) successfully closes the connection. If you call `conn.close()`, you'll get both a 'disconnected' event and a 'close' event.
* `reconnected`: Emitted if Mongoose lost connectivity to MongoDB and successfully reconnected. Mongoose attempts to [automatically reconnect](https://thecodebarbarian.com/managing-connections-with-the-mongodb-node-driver.html) when it loses connection to the database.
* `error`: Emitted if an error occurs on a connection, like a `parseError` due to malformed data or a payload larger than [16MB](https://docs.mongodb.com/manual/reference/limits/#BSON-Document-Size).
* `fullsetup`: Emitted when you're connecting to a replica set and Mongoose has successfully connected to the primary and at least one secondary.
* `all`: Emitted when you're connecting to a replica set and Mongoose has successfully connected to all servers specified in your connection string.
* `reconnectFailed`: Emitted when you're connected to a standalone server and Mongoose has run out of [`reconnectTries`](https://thecodebarbarian.com/managing-connections-with-the-mongodb-node-driver.html#handling-single-server-outages). The [MongoDB driver](http://npmjs.com/package/mongodb) will no longer attempt to reconnect after this event is emitted. This event will never be emitted if you're connected to a replica set.
<h3 id="keepAlive"><a href="#keepAlive">A note about keepAlive</a></h3>
For long running applications, it is often prudent to enable `keepAlive`
with a number of milliseconds. Without it, after some period of time
you may start to see `"connection closed"` errors for what seems like
no reason. If so, after
[reading this](http://tldp.org/HOWTO/TCP-Keepalive-HOWTO/overview.html),
you may decide to enable `keepAlive`:
```javascript
mongoose.connect(uri, { keepAlive: true, keepAliveInitialDelay: 300000 });
```
`keepAliveInitialDelay` is the number of milliseconds to wait before initiating `keepAlive` on the socket.
`keepAlive` is true by default since mongoose 5.2.0.
<h3 id="replicaset_connections"><a href="#replicaset_connections">Replica Set Connections</a></h3>
To connect to a replica set you pass a comma delimited list of hosts to
connect to rather than a single host.
```javascript
mongoose.connect('mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]' [, options]);
```
For example:
```javascript
mongoose.connect('mongodb://user:pw@host1.com:27017,host2.com:27017,host3.com:27017/testdb');
```
To connect to a single node replica set, specify the `replicaSet` option.
```javascript
mongoose.connect('mongodb://host1:port1/?replicaSet=rsName');
```
<h3 id="replicaset-hostnames"><a href="#replicaset-hostnames">Replica Set Host Names</a></h3>
MongoDB replica sets rely on being able to reliably figure out the domain name
for each member. On Linux and OSX, the MongoDB server uses the output of the
[`hostname` command](https://linux.die.net/man/1/hostname) to figure out the
domain name to report to the replica set. This can cause confusing errors
if you're connecting to a remote MongoDB replica set running on a machine that
reports its `hostname` as `localhost`:
```
// Can get this error even if your connection string doesn't include
// `localhost` if `rs.conf()` reports that one replica set member has
// `localhost` as its host name.
failed to connect to server [localhost:27017] on first connect
```
If you're experiencing a similar error, connect to the replica set using the
`mongo` shell and run the
[`rs.conf()`](https://docs.mongodb.com/manual/reference/method/rs.conf/) command to check the host names of each replica set member. Follow
[this page's instructions to change a replica set member's host name](https://docs.mongodb.com/manual/tutorial/change-hostnames-in-a-replica-set/#change-hostnames-while-maintaining-replica-set-availability).
<h3 id="mongos_connections"><a href="#mongos_connections">Multi-mongos support</a></h3>
You can also connect to multiple [mongos](https://docs.mongodb.com/manual/reference/program/mongos/) instances
for high availability in a sharded cluster. You do
[not need to pass any special options to connect to multiple mongos](http://mongodb.github.io/node-mongodb-native/3.0/tutorials/connect/#connect-to-sharded-cluster) in mongoose 5.x.
```javascript
// Connect to 2 mongos servers
mongoose.connect('mongodb://mongosA:27501,mongosB:27501', cb);
```
<h3 id="multiple_connections"><a href="#multiple_connections">Multiple connections</a></h3>
So far we've seen how to connect to MongoDB using Mongoose's default
connection. At times we may need multiple connections open to Mongo, each
with different read/write settings, or maybe just to different databases for
example. In these cases we can utilize `mongoose.createConnection()` which
accepts all the arguments already discussed and returns a fresh connection
for you.
```javascript
const conn = mongoose.createConnection('mongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]', options);
```
This [connection](./api.html#connection_Connection) object is then used to
create and retrieve [models](./api.html#model_Model). Models are
**always** scoped to a single connection.
```javascript
const UserModel = conn.model('User', userSchema);
```
If you use multiple connections, you should make sure you export schemas,
**not** models.
```javascript
const userSchema = new Schema({ name: String, email: String });
// The correct pattern is to export a schema
module.exports = userSchema;
// Because if you export a model as shown below, the model will be scoped
// to Mongoose's default connection.
// module.exports = mongoose.model('User', userSchema);
```
In addition, you should define a factory function that registers models on a
connection to make it easy to register all your models on a given connection.
```javascript
const userSchema = require('./userSchema');
module.exports = conn => {
conn.model('User', userSchema);
};
```
Mongoose creates a _default connection_ when you call `mongoose.connect()`.
You can access the default connection using `mongoose.connection`.
<h3 id="connection_pools"><a href="#connection_pools">Connection Pools</a></h3>
Each `connection`, whether created with `mongoose.connect` or
`mongoose.createConnection` are all backed by an internal configurable
connection pool defaulting to a maximum size of 5. Adjust the pool size
using your connection options:
```javascript
// With object options
mongoose.createConnection(uri, { poolSize: 4 });
const uri = 'mongodb://localhost:27017/test?poolSize=4';
mongoose.createConnection(uri);
```
<h3 id="v5-changes"><a href="#v5-changes">Option Changes in v5.x</a></h3>
You may see the following deprecation warning if upgrading from 4.x to 5.x
and you didn't use the `useMongoClient` option in 4.x:
```
the server/replset/mongos options are deprecated, all their options are supported at the top level of the options object
```
In older version of the MongoDB driver you had to specify distinct options
for server connections, replica set connections, and mongos connections:
```javascript
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
}
});
```
In mongoose v5.x you can instead declare these options at the top level,
without all that extra nesting.
[Here's the list of all supported options](http://mongodb.github.io/node-mongodb-native/2.2/api/MongoClient.html).
```javascript
// Equivalent to the above code
mongoose.connect(myUri, {
socketTimeoutMS: 0,
keepAlive: true,
reconnectTries: 30
});
```
<h3 id="next">Next Up</h3>
Now that we've covered connections, let's take a look at [models](/docs/models.html).