In my app I have a method for allowing the admin to download a CSV of the users assigned to him. It consists of two database queries, three lodash loops to to process it, and an unparsing of the object to CSV via baby parse. It then returns that string from the method where it is downloaded by a client.
On my local machine with a small test database this works without issue. On the production site this operation is querying about 12 MB of data, about 14,000 records, but it takes about 4 minutes for the Method to run, with the CPU at 100% and causing other connected users to wait for the app to function. It seems to have gotten this bad particularly when we moved from a mupx deployement on Azure to Galaxy (yes, even after migrating our database). Kadira logs are inconsistent with actual experience of the overall time it takes the method to respond, but it does claim that it takes about 7 seconds for one query and 3 seconds for the other.
Does anyone have an idea what could be causing these performance issues? The method is below. Thanks for the help!
const getCustomerCsv = new ValidatedMethod({
name: 'getCustomerCsv',
validate: null,
run() {
this.unblock();
if (Meteor.isServer) {
const query = { ... };
const rawData = Meteor.users.find(query,
{ fields: { emails: 1, profile: 1 } }
).fetch();
const childIds = _(rawData).map((obj) => obj.profile.children)
.flatten()
.uniq()
.value();
const children = Children.find({ _id: { $in: childIds } },
{ fields: { name: 1, dob: 1 } }).fetch();
const maxChildren = (_.maxBy(rawData, (user) => user.profile.children.length))
.profile.children.length;
const data = _(rawData).map((user, rawI) => {
const ret = {
// build CSV object strcture ...
};
// Assign children to data structure
const len = user.profile.children.length;
for (let i = 0; i < len; i++) {
const childId = user.profile.children[i];
const child = _.find(children, ['_id', childId]);
ret[`child${i}`] = `${child.name.first} ${child.name.last}`;
ret[`dob${i}`] = moment(child.dob).format('YYYY-MM-DD');
}
// create keys for remaining children structure so it will unparse to csv correctly
for (let i = len; i < maxChildren; i++) {
ret[`child${i}`] = '';
ret[`dob${i}`] = '';
}
// delete raw data to free room in memory. All copy operations are primitive types
delete rawData[rawI];
return ret;
}).value();
return Baby.unparse(data);
}
return false;
},
});