Skip to main content

Deprecation Warnings in MongoDB's Node.js API

5 min read

Older Article

This article was published 8 years ago. Some information may be outdated or no longer applicable.

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:

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:

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:

// 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 } }
// 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:

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.