CHANGES_3.0.0.md 10.3 KB

Features

The following are new features added in MongoDB 3.6 and supported in the Node.js driver.

Retryable Writes

Support has been added for retryable writes through the connection string. MongoDB 3.6 will utilize server sessions to allow some write commands to specify a transaction ID to enforce at-most-once semantics for the write operation(s) and allow for retrying the operation if the driver fails to obtain a write result (e.g. network error or "not master" error after a replica set failover)Full details can be found in the Retryable Writes Specification.

DNS Seedlist Support

Support has been added for DNS Seedlists. Users may now configure a single domain to return a list of host names. Full details can be found in the Seedlist Discovery Specification.

Change Streams

Support has been added for creating a stream to track changes to a particular collection. This is a new feature in MongoDB 3.6. Full details can be found in the Change Stream Specification as well as examples in the test directory.

Sessions

Version 3.6 of the server introduces the concept of logical sessions for clients. In this driver, MongoClient now tracks all sessions created on the client, and explicitly cleans them up upon client close. More information can be found in the Driver Sessions Specification.

API Changes

We removed the following API methods.

  • Db.prototype.authenticate
  • Db.prototype.logout
  • Db.prototype.open
  • Db.prototype.db
  • Db.prototype.close
  • Admin.prototype.authenticate
  • Admin.prototype.logout
  • Admin.prototype.profilingLevel
  • Admin.prototype.setProfilingLevel
  • Admin.prototype.profilingInfo
  • Cursor.prototype.nextObject

We've added the following API methods.

  • MongoClient.prototype.logout
  • MongoClient.prototype.isConnected
  • MongoClient.prototype.db
  • MongoClient.prototype.close
  • MongoClient.prototype.connect
  • Db.prototype.profilingLevel
  • Db.prototype.setProfilingLevel
  • Db.prototype.profilingInfo

In core we have removed the possibility of authenticating multiple credentials against the same connection pool. This is to avoid problems with MongoDB 3.6 or higher where all users will reside in the admin database and thus database level authentication is no longer supported.

The legacy construct

var db = var Db('test', new Server('localhost', 27017));
db.open((err, db) => {
  // Authenticate
  db.admin().authenticate('root', 'root', (err, success) => {
    ....
  });
});

is replaced with

new MongoClient(new Server('localhost', 27017), {
    user: 'root'
  , password: 'root'
  , authSource: 'adming'}).connect((err, client) => {
    ....
  })

MongoClient.connect works as expected but it returns the MongoClient instance instead of a database object.

The legacy operation

MongoClient.connect('mongodb://localhost:27017/test', (err, db) => {
  // Database returned
});

is replaced with

MongoClient.connect('mongodb://localhost:27017/test', (err, client) => {
  // Client returned
  var db = client.db('test');
});

Other Changes

Below are more updates to the driver in the 3.0.0 release.

Connection String

Following changes to the MongoDB connection string specification, authentication and hostname details in connection strings must now be URL-encoded. These changes reduce ambiguity in connection strings.

For example, whereas before mongodb://u$ername:pa$$w{}rd@/tmp/mongodb-27017.sock/test would have been a valid connection string (with username u$ername, password pa$$w{}rd, host /tmp/mongodb-27017.sock and auth database test), the connection string for those details would now have to be provided to MongoClient as mongodb://u%24ername:pa%24%24w%7B%7Drd@%2Ftmp%2Fmongodb-27017.sock/test.

Unsupported URL options in a connection string now log a warning instead of throwing an error.

For more information about connection strings, read the connection string specification.

BulkWriteResult & BulkWriteError

When errors occured with bulk write operations in the past, the driver would callback or reject with the first write error, as well as passing the resulting BulkWriteResult. For example:

MongoClient.connect('mongodb://localhost', function(err, client) {
  const collection = client.db('foo').collection('test-collection')

  collection
    .insert({ id: 1 })
    .then(() => collection.insertMany([ { id: 1 }, { id: 1 } ]))
    .then(result => /* deal with errors in `result */)
    .catch(err => /* no error is thrown for bulk errors */);
});

becomes:

MongoClient.connect('mongodb://localhost', function(err, client) {
  const collection = client.db('foo').collection('test-collection')

  collection
    .insert({ id: 1 })
    .then(() => collection.insertMany([ { id: 1 }, { id: 1 } ]))
    .then(() => /* this will not be called in the event of a bulk write error */)
    .catch(err => /* deal with errors in `err` */);
});

Where the result of the failed operation is a BulkWriteError which has a child value result which is the original BulkWriteResult. Similarly, the callback form no longer calls back with an (Error, BulkWriteResult), but instead just a (BulkWriteError).

mapReduce inlined results

When Collection.prototype.mapReduce is invoked with a callback that includes out: 'inline', it would diverge from the Promise-based variant by returning additional data as positional arguments to the callback ((err, result, stats, ...)). This is no longer the case, both variants of the method will now return a single object for all results - a single value for the default case, and an object similar to the existing Promise form for cases where there is more data to pass to the user.

Find

find and findOne no longer support the fields parameter. You can achieve the same results as the fields parameter by using Cursor.prototype.project or by passing the projection property in on the options object . Additionally, find does not support individual options like skip and limit as positional parameters. You must either pass in these parameters in the options object, or add them via Cursor methods like Cursor.prototype.skip.

Collection.prototype.aggregate

Collection.prototype.aggregate no longer accepts variadic arguments. While this was originally added to improve compatibility with the mongo shell, it has never been a documented feature, and has led to more bugs and maintenance burden. Pipeline stages are now only accepted as an Array of stages as the first argument.

2.x syntax:

collection.prototype.aggregate(
  {$match: {a: 1}},
  {$project: {b: 1, _id: 0}},
  function (err, result) {
    ...
  }
);

3.x syntax

collection.prototype.aggregate(
  [
    {$match: {a: 1}},
    {$project: {b: 1, _id: 0}}
  ],
  function (err, cursor) {
    ...
  }
);

Collection.prototype.aggregate now returns a cursor if a callback is provided. It used to return the resulting documents which is the same as calling cursor.toArray() on the cursor we now pass to the callback.

2.x syntax

collection.prototype.aggregate(
  [
    {$match: {a: 1}},
    {$project: {b: 1, _id: 0}}
  ],
  function (err, result) {
    console.log(result);
  }
);

3.x syntax

collection.prototype.aggregate(
  [
    {$match: {a: 1}},
    {$project: {b: 1, _id: 0}}
  ],
  function (err, cursor) {
    cursor.toArray(function(err, result) {
      console.log(result);
    });
  }
);

Support added for comment in the aggregation command. Support also added for a hint field in the aggregation options.

If you use aggregation and try to use the explain flag while you have a readConcern or writeConcern, your query will now fail.

updateOne & updateMany

The driver now ensures that updated documents contain atomic operators. For instance, if a user tries to update an existing document but passes in no operations (such as $set, $unset, or $rename), the driver will now error:


let testCollection = db.collection('test');
testCollection.updateOne({_id: 'test'}, {});
// An error is returned: The update operation document must contain at least one atomic operator.

keepAlive

Wherever it occurs, the option keepAlive has been changed. keepAlive is now a boolean that enables/disables keepAlive, while keepAliveInitialDelay specifies how long to wait before initiating keepAlive. This brings the API in line with NodeJS's socket api

insertMany

Now insertMany returns insertedIds in a map of the index of the inserted document to the id of the inserted document:

{
  "0": 2,
  "1": 3
}

Previously an array of ids was returned: [ 2, 3 ]. This change occurs with both ordered and unordered insertMany calls, see the CRUD specifications for more details.

geoNear command helper

The functionality of the geoNear command is duplicated elsewhere in the language, in the $near/$nearSphere query operators on unsharded collections, and in the $geoNear aggregation stage on all collections. Maintaining this command increases our test surface, and creates additional work when adding features that must be supported on all read commands. As a result, the command will be fully removed in the MongoDB 4.0 release, and we are choosing to remove it in this major release of the node driver.

Tests

We have updated all of the tests to use Mocha and a new test runner, mongodb-test-runner, which sets up topologies for the test scenarios.