# Deprecation Warnings in MongoDB's Node.js API

Source: https://tpiros.dev/blog/deprecation-warnings-in-mongodbs-node-js-api

Install the latest MongoDB Node.js API (v3.x.x and above) and you'll likely run into deprecation warnings. They'll show up when you connect to the database, when you run queries, sometimes both at once.

These warnings are a natural side effect of the API changing under the hood. The good news: they're all fixable.

> Note that most of these deprecation warnings appear in version 3.x.x and above of the Node.js API when paired with MongoDB version 4.x and above.

# `db.collection` is not a function

You'll hit this one after skipping a few major versions. In older versions of the API, `connect()` handed back a database object directly. The latest version hands back a client object instead, and you pull the database off that.

The correct implementation looks like this:

```javascript
const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017';

MongoClient.connect(url)
  .then((client) => {
    const db = client.db('my-db'); // select database
    const collection = db.collection('my-collection'); // select collection
    return collection.find({}).limit(1).toArray(); // then query
  })
  .then((response) => console.log(response))
  .catch((error) => console.error(error));
```

# DeprecationWarning: current URL string parser is deprecated

MongoDB now enforces the port number as part of the connection string. The old URL parser is being retired. To switch to the new one, pass an option to the `connect()` method:

```javascript
const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017';

// added { useNewUrlParser: true }
MongoClient.connect(url, { useNewUrlParser: true })
  .then((client) => {
    const db = client.db('my-db');
    const collection = db.collection('my-collection');
    return collection.find({}).limit(1).toArray();
  })
  .then((response) => console.log(response))
  .catch((error) => console.error(error));
```

# DeprecationWarning: collection.[method] is deprecated

A bunch of methods fall into this bucket:

- `collection.insert` - use `insertOne`, `insertMany` or `bulkWrite` instead
- `collection.save` - use `insertOne`, `insertMany`, `updateOne`, or `updateMany ` instead
- `collection.update` - use `updateOne`, `updateMany`, or `bulkWrite` instead
- `collection.remove` - use `deleteOne`, `deleteMany`, or `bulkWrite` instead

Each suggestion nudges you toward picking the right method for the right job. It makes the code more readable too.

Some of the new methods are obvious. Want to insert one record? Use `insertOne`. Others need a closer look. What's the actual difference between `insertMany` and `bulkWrite` when inserting data?

Let's break that down.

# `insertMany` / `updateMany` / `deleteMany` vs `bulkWrite`

Every warning in the previous section suggested `bulkWrite` as an option. That's curious. How does `bulkWrite` differ from `insertMany` or `updateMany`?

It comes down to function signatures. With `insertMany` (and the other specific methods), you pass in multiple documents as an array. With `bulkWrite`, you pass in multiple **operations**.

The accepted operations are: `insertOne`, `updateOne`, `updateMany`, `deleteOne`, `deleteMany` and `replaceOne`. So `bulkWrite` can handle all of these, and mix them together in a single call.

Here's what that looks like:

```javascript
// insertMany
MongoClient.connect(url, { useNewUrlParser: true })
  .then((client) => {
    const db = client.db('star-wars');
    const collection = db.collection('characters');
    const documents = [
      {
        name: 'Jack',
        age: 23,
      },
      {
        name: 'Kate',
        age: 29,
      },
    ];
    return collection.insertMany(documents);
  })
  .then((response) => console.log(response))
  .catch((error) => console.error(error));
```

That snippet returns the operation details along with the IDs of the inserted documents:

```
{ result: { ok: 1, n: 2 },
  ops:
    [ { name: 'Jack', age: 23, _id: 5b9fcf4d2f38660e22a01b54 },
      { name: 'Kate', age: 29, _id: 5b9fcf4d2f38660e22a01b55 } ],
  insertedCount: 2,
  insertedIds:
    { '0': 5b9fcf4d2f38660e22a01b54, '1': 5b9fcf4d2f38660e22a01b55 } }
```

```javascript
// bulkWrite with insertOne
MongoClient.connect(url, { useNewUrlParser: true })
  .then((client) => {
    const db = client.db('star-wars');
    const collection = db.collection('characters');
    const documents = [
      {
        name: 'Jack',
        age: 23,
      },
      {
        name: 'Kate',
        age: 29,
      },
    ];
    return collection.bulkWrite([
      {
        insertOne: {
          document: documents[0],
        },
      },
      {
        insertOne: {
          document: documents[1],
        },
      },
    ]);
  })
  .then((response) => console.log(response))
  .catch((error) => console.error(error));
```

> Note that it'd make more sense to include the operation in the data structure itself, but here we're sticking with the same example throughout and accessing document data via array indexes.

That returns a `BulkWriteResult` object with details about the operations (in our case, just inserts):

```
BulkWriteResult {
  result:
    { ok: 1,
      writeErrors: [],
      writeConcernErrors: [],
      insertedIds: [ [Object], [Object] ],
      nInserted: 2,
      nUpserted: 0,
      nMatched: 0,
      nModified: 0,
      nRemoved: 0,
      upserted: [] },
  insertedCount: 2,
  matchedCount: 0,
  modifiedCount: 0,
  deletedCount: 0,
  upsertedCount: 0,
  upsertedIds: {},
  insertedIds:
    { '0': 5b9fd080f935210e3c59a35f, '1': 5b9fd080f935210e3c59a360 },
  n: 2 }
```

So `bulkWrite` can chain multiple operations together with barely any extra effort:

```javascript
MongoClient.connect(url, { useNewUrlParser: true })
  .then((client) => {
    const db = client.db('star-wars');
    const collection = db.collection('characters');
    const documents = [
      {
        name: 'Jack',
        age: 23,
      },
      {
        name: 'Kate',
        age: 29,
      },
    ];
    return collection.bulkWrite([
      {
        insertOne: {
          document: documents[0],
        },
      },
      {
        insertOne: {
          document: documents[1],
        },
      },
      {
        updateOne: {
          filter: { name: 'Kate' },
          update: { $set: { age: 25 } },
        },
      },
    ]);
  })
  .then((response) => console.log(response))
  .catch((error) => console.error(error));
```

That inserts two documents and updates one of them (the document we just inserted) in a single call. Here's the returned data structure:

```
// trimmed
BulkWriteResult {
  result:
    { ok: 1,
      insertedIds: [ [Object], [Object] ],
      nInserted: 2,
      nMatched: 1,
      nModified: 1,
      upserted: [] },
  insertedCount: 2,
  matchedCount: 1,
  modifiedCount: 1,
// ...
```

# Conclusion

That covers the main errors and warnings you'll hit when updating to the latest MongoDB and its Node.js API. Most fixes take a single line change. The `bulkWrite` method is worth knowing about even if you don't need it right away.
