I'm trying to do a Typeorm query depending on an element of an object but I have an issue with the forEach
and the async function.
I have read a lot of similar issues but no one worked for me as expected.
Here is my code snippet with the await not allowed in a forEach
:
public async runBudgetLimit(): Promise<void> {
const contracts: ContractEntity[] = await this.contractService.getAllProjects();
contracts.forEach((contract) => {
const project: UserEntity = await this.userService.findOne(contract.milestoneId);
const date: string = Time.moment().format('YYYY-MM-DD');
const budgetUsed = this.trackService.getBillingByProject(project.contractId, date, '1000', '1000', true);
});
}
Here is the async Typeorm query:
async findOne(id: string): Promise<UserEntity | undefined> {
return this.userRepository.findOne(id);
}
I don't know what is the best solution to solve this issue, I don't think that the for loop is a good solution but I'm open to all solutions.
You can just use for-of
loop like this:
for (const contract of contracts) {
const project: UserEntity = await this.userService.findOne(contract.milestoneId);
const date: string = Time.moment().format('YYYY-MM-DD');
const budgetUsed = this.trackService.getBillingByProject(project.contractId, date, '1000', '1000', true);
}
Or with slight optimisations - check this answer for differences between for-of
and Promise.all
approaches:
await Promise.all(contracts.map(async contract => {
const project: UserEntity = await this.userService.findOne(contract.milestoneId);
const date: string = Time.moment().format('YYYY-MM-DD');
const budgetUsed = this.trackService.getBillingByProject(project.contractId, date, '1000', '1000', true);
}));
Keep in mind that these solutions are not optimal in some cases, because by getting UserEntity for every contract there is an additional query to the database AKA N+1 query problem
. To fix this you can load all of the users along with the contracts by using the relations array.
I am not sure why are you getting contractId
from the project, isn't it available on the contract
object?
Also if the response from getBillingByProject
is a promise you should put await
in front