Files
meteor/guide/source/2.8-migration.md
Matheus Castro 1c590919b8 # Conflicts:
#	packages/mongo/mongo_driver.js
2022-10-17 17:27:41 -03:00

7.5 KiB

title, description
title description
Migrating to Meteor 2.8 How to migrate your application to Meteor 2.8.

Meteor 2.8 introduce the new MongoDB Package Async API. For a complete breakdown of the changes, please refer to the changelog.

For this new async API, we have new methods like findOneAsync, which behaves exactly like the findOne method, but it now returns a promise that needs to be resolved to get the data.

Why this is important?

You may know that on Meteor we use a package called Fibers. This package is what makes possible to call async function, like db.findOne(), inside Meteor in a sync way (without having to wait for the promise to resolve).

But starting from Node 16, Fibers will stop working, so Meteor needs to move away from Fibers, otherwise, we'll be stuck on Node 14.

If you want to know more about the plan, you can check this discussion.

Why doing this now?

This will be a considerable change for older Meteor applications, and some parts of the code of any Meteor app will have to be adjusted eventually. So it's important to start the migration process now.

With this version, you'll be able to start preparing your app for the future by replacing your current MongoDB methods with the new async ones.

What's new?

Here are the newly added methods (you can see this description and the code here):

Added async methods on collections.

  • All async methods have an Async suffix to their names. These are: createCappedCollectionAsync, createIndexAsync, dropCollectionAsync, dropIndexAsync, findOneAsync, insertAsync, removeAsync, updateAsync, and upsertAsync.

Added async methods on cursors.

  • All async methods have an Async suffix to their names. These are: countAsync, fetchAsync, forEachAsync, and mapAsync.
  • There's also [Symbol.asyncIterator], so this code should work:
    for await (const document of collection.find(query, options)) /* ... */
    

There is also a new Meteor method called callAsync. It should be used to call async methods.

How can I start using these new features?

We got a few examples for making it easy to use these new feature, you can look the code snippet bellow

// SERVER

// Before 2.8, we would use something like this
export const removeByID = ({ id }) => {
  SomeCollection.remove({ _id: id });
};

// Now we can also do like this
export const removeByIDAsync = async ({ id }) => {
  await SomeCollection.removeAsync({ _id: id });
};

Meteor.methods({
   //...
   removeByID,
   removeByIDAsync,
});

// CLIENT

const result = Meteor.call('removeByID', { id });

// For the async, you call it like this:

const result = await Meteor.callAsync('removeByIDAsync', { id });

// or even like this:

Meteor.callAsync('removeByIDAsync', { id }).then(result => {
   console.log(result);
});

More examples can be retrieved from this commit.

The callAsync limitations

You should never call a method if another method is still running, you need to be sure that only one method is running each time. So, for example:

// This is ok:

Meteor.call('removeByID', { id }, (error, result) => {
   // do something
});
Meteor.callAsync('removeByIDAsync', { id }).then(result => {
   // do something
});

// This is NOT ok:

Meteor.callAsync('removeByIDAsync', { id }).then(result => {
   // do something
});
Meteor.call('removeByID', { id }, (error, result) => {
  // do something
});

// instead, do it like this:

await Meteor.callAsync('removeByIDAsync', { id });
Meteor.call('removeByID', { id }, (error, result) => {
   // do something
});

// or this

Meteor.callAsync('removeByIDAsync', { id }).then(result => {
   // do something
   Meteor.call('removeByID', { id }, (error, result) => {
      // do something
   });
});

As callAsync returns a promise, it'll be solved in the future. So you need to wait until it finishes before calling another method (async or not).

If you wish to understand why this limitation exist, you can read this comment in the PR that created the callAsync.

It's also important to understand what will happen if you call an async method with Meteor.call, and vice versa.

If you can an async method with Meteor.call in the client, and you don't have the package insecure on your project, an error like this will be thrown:

This error is thrown because when Meteor.call execute your async method, the method will return a promise. Then, when your method run in the future, it won't have the global contexts anymore. Meaning that if you have some MongoDB method, for example, inside your async method, it will run outside a stub.

It would the equivalent of running something like this directly on the client: SomeCollection.remove({ _id: id }). Hence, the error. If you have the insecure package on your project, this error won't show up because insecure allows your app to run write methods from the client.

In the server it's fine to call an async method using Meteor.call().

About Meteor.callAsync(), is fine to call it with a sync method either from the client or server.

Our recommendation for the future

We recommend that you start to write new methods and publications using async from this version forward, forcing internal APIs to also be async with time. And, of course, also updating your current ones. As soon you start, the better.

Can I update to this version without changing my app?

Yes. You can update to this version without changing your app.

Migrating from a version older than 2.8?

If you're migrating from a version of Meteor older than Meteor 2.8, there may be important considerations not listed in this guide. Please review the older migration guides for details: