Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment

#1
let self=this;
Orders.aggregate({[...]}).forEach((item)={
    if(item.type===3){

         let status=Meteor.call("order/query",item.OrderNo); //throw error Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.

         item["Status"]=status;
     }
self.added("Orders",item._id,item);
});
self.ready();
#2

forEach takes a callback function as it’s argument, so you should do what the error message says and wrap the callback with Meteor.bindEnvironment like so:

let self=this;
Orders.aggregate({[...]}).forEach(Meteor.bindEnvironment((item)={
//                                ^^^^^^^^^^^^^^^^^^^^^^ 
// Pass callback function to Meteor.bindEnvironment
    if(item.type===3){

        let status=Meteor.call("order/query",item.OrderNo); 
        item["Status"]=status;
    }
    self.added("Orders",item._id,item);
})); // extra close bracket for the call to bindEnvironment
self.ready();
#3

but that is dont work; :laughing::laughing:

#4

What error is it giving?

Where does the aggregate function come from? It’s not normally on a Meteor collection

#5

const Orders = new Mongo.Collection(‘Orders’);

#6

What packages do you have installed?
If I run Mongo.Collection(‘Orders’); the returned object doesn’t have an aggregate method

#7

@tlxfif: are you using the meteorhacks:aggregate package?

That hasn’t been updated in 3 years and the underlying MongoDB aggregation result has changed in that time.

If you want to roll your own publication, use the underlying aggregate method on rawCollection. Something like:

Meteor.publish('doAggregation', async function () {
  const rawOrders = Orders.rawCollection();
  await rawOrders.aggregate({[...]}).toArray().forEach(Meteor.bindEnvironment(item => {
    if (item.type === 3) {
      let status = Meteor.call("order/query", item.OrderNo);
      item["Status"] = status;
    }
    this.added("Orders", item._id, item);
  }));
  this.ready();
});

However, I would also look into removing/replacing the Meteor.call, either by refactoring the method code to call a function, which you would then call in the above code, or by adding the resolution of the status from the item.OrderNo into the aggregation pipeline if possible. That latter would be my preferred solution as it leverages the database engine to the work it was designed to do and completely removes any dependency on Fibers and Meteor.bindEnvironment.

Meteor.publish('doAggregation', async function () {
  const rawOrders = Orders.rawCollection();
  await rawOrders.aggregate({[...]}).toArray().forEach(item => {
    this.added("Orders", item._id, item);
  });
  this.ready();
});

Caveat I may have misunderstood or missed something.

1 Like
#8

thanks :hugs::hugs::hugs:

1 Like