bp123
bp123

Reputation: 3427

wrapAsync return function not result

Alright, noob here. Still learning. I don't understand how I get my method to return the result of my Meteor.wrapAsync function to the Meteor.call on the client. My console.log(companies); in my method produces a function and not the result. What am I not understanding here?

Path: client.jsx

Meteor.call('getTop100ASX', (error, result) => {
  console.log(result);
});

Path: method.js

Meteor.methods({
  'getTop100ASX'() {
    const aggregateFunc = db.collection('companiesASX').aggregate([{
      $group: {
        _id: {
          location: "$google_maps.geometry_location"
        },
        companies: {
          $addToSet: {
            name: "$company_name"
          }
        }
      }
    }]).toArray((err, result) => {
      return result;
    });

    const companies = Meteor.wrapAsync(aggregateFunc);

    console.log(companies);

    return companies;
  },
});

Upvotes: 1

Views: 822

Answers (1)

MasterAM
MasterAM

Reputation: 16488

wrapAsync wraps a function that would normally take a callback and makes it possible to call that wrapped function on the server in a synchronous fashion, utilizing fibers (i.e, takes a function + context and returns a function).

It cannot take some value and magically extract the intended result from it (i.e, in your example, the the result from the toArray callback).

What you gave it is not a function, but a Promise object (that was returned from the call to toArray).

Since it already returns a promise, you have several options:

The simpler one is to return that promise (and there is no need for the callback in toArray()), since if a Meteor method returns a promise, the server will wait for the promise to resolve and then returns the result to the client.

Meteor.methods({
  'getTop100ASX'() {
    return db.collection('companiesASX').aggregate([...]).toArray();
  },
});

If you need to further process companies in the method, you could use async/await, something like:

Meteor.methods({
  async 'getTop100ASX'() {
    const companies = await db.collection('companiesASX').aggregate([{
      $group: {
        _id: {
          location: "$google_maps.geometry_location"
        },
        companies: {
          $addToSet: {
            name: "$company_name"
          }
        }
      }
    }]).toArray();

    let someResult = sumeFunc(companies);

    return someResult;
  },
});

For completeness, in order to use wrapAsync, you should have supplied the toArray method and the context like so:

Meteor.methods({
  'getTop100ASX'() {
    const cursor = db.collection('companiesASX').aggregate([{
      $group: {
        _id: {
          location: "$google_maps.geometry_location"
        },
        companies: {
          $addToSet: {
            name: "$company_name"
          }
        }
      }
    }]);

    // wrap the cursor's `toArray` method and preservs the context
    const syncToArray = Meteor.wrapAsync(cursor.toArray, cursor);

    // and call the wrapped function in a sync manner
    const companies = syncToArray();

    return companies;
  },
});

Upvotes: 2

Related Questions