【问题标题】:Nestjs controller async problemsNestjs控制器异步问题
【发布时间】:2021-05-11 22:33:59
【问题描述】:

我目前正在编写一个财务跟踪应用程序,并从 CSV 文件构建了一个数据导入,用于检查数据库中是否已经存在条目,如果没有,则将某个类别添加到条目中,然后将其保存到数据库中。

导入 CSV 文件后,我想输出作为对发布请求的响应:导入条目的数量以及未找到合适类别的所有条目。不幸的是,由于 Nestjs 的异步方法,我失败了。但是,我的响应是在其他功能完成之前输出的。这样第一个导入总是“imports: 0”和“unsortedTransactions: []。 ”

如何在控制器中等待所有功能完成后再返回响应? 事务控制器:

@Controller('transactions')
export class TransactionController {
  constructor(
    private transactionService: TransactionService,
    private labelService: LabelService,
  ) {}

  @Post()
  @UseInterceptors(
    FileInterceptor('file', {
      storage: diskStorage({
        destination: './uploads/csv',
        filename: randomFilename,
      }),
    }),
  )
  public createTransactions(
    @Response() response,
    @UploadedFile() file,
    @Request() request,
  ) {
    let imports = 0;

    fs.createReadStream(path.resolve(file.path), {
      encoding: 'utf-8',
    })
      .pipe(csv.parse({ headers: false, delimiter: ';', skipRows: 1 }))
      .on('data', (data) => {
        const timestamp = new Date()
          .toISOString()
          .slice(0, 19)
          .replace('T', ' ');
        const amount = parseFloat(data[14].replace(',', '.'));
        const bankaccountId = request.body.bankaccount_id;
        const bookingDate = this.createDate(data[1]);
        const name = data[11].replace(/\s\s+/g, ' ');
        const usage = data[4].replace(/\s\s+/g, ' ');

        this.transactionService
          .checkDuplicate(amount, name, usage, bookingDate)
          .then((entry) => {
            if (entry.length === 0) {
              this.sortLabel(data).then((label_id) => {
                const newTransaction = {
                  amount,
                  name,
                  usage,
                  label_id,
                  bankaccount_id: bankaccountId,
                  booking_date: bookingDate,
                  created_at: timestamp,
                  updated_at: timestamp,
                };

                this.transactionService.create(newTransaction);
                imports++;
              });
            }
          });
      });

    const unsortedTransactions = this.transactionService.getUnsorted();
    return response.send({ unsortedTransactions, imports });
  }

  private async sortLabel(transaction: Transaction): Promise<any> {
    let label_id = 1;
    const labels = await this.labelService.getAll();
    const name = transaction[11].replace(/\s\s+/g, ' ').toLowerCase();
    const usage = transaction[4].replace(/\s\s+/g, ' ').toLowerCase();

    labels.forEach((label) => {
      if (label.keywords != null) {
        const keywords = label.keywords.split(',');

        keywords.forEach((keyword) => {
          if (
            name.includes(keyword.toLowerCase()) ||
            usage.includes(keyword.toLowerCase())
          ) {
            label_id = label.id;
          }
        });
      }
    });

    return await label_id;
  }

  private createDate(date: string): string {
    const dateArray = date.split('.');

    return `20${dateArray[2]}-${dateArray[1]}-${dateArray[0]}`;
  }
}

交易服务:

export class TransactionService {
  constructor(
    @InjectRepository(Transaction)
    private readonly transactionRepository: Repository<Transaction>,
  ) {}

  public create(transaction): Promise<Transaction> {
    return this.transactionRepository.save(transaction);
  }

  public getAll(): Promise<Transaction[]> {
    return this.transactionRepository.find({
      relations: ['label_id', 'bankaccount_id'],
    });
  }

  public getUnsorted(): Promise<Transaction[]> {
    return this.transactionRepository.find({
      where: {
        label_id: 1,
      },
    });
  }

  public checkDuplicate(
    amount: number,
    name: string,
    usage: string,
    booking_date: string,
  ): Promise<Transaction[]> {
    return this.transactionRepository.find({
      where: {
        amount,
        name,
        usage,
        booking_date,
      },
    });
  }
}

【问题讨论】:

  • 太复杂了,你用的是哪个数据库?如果条目存在,findOne 可以检查(续集)。
  • 我使用的是 mySQL 数据库

标签: javascript typescript async-await promise nestjs


【解决方案1】:

您需要利用 js 中的 async / await 功能。您正在从您的服务中返回承诺,所以这很容易。

进行以下更改

将 async 关键字添加到函数中。 (这样你就可以await里面的其他函数了)

  public createTransactions(
    @Response() response,
    @UploadedFile() file,
    @Request() request,
  ) async {....
  fs.createReadStream(path.resolve(file.path), {
      encoding: 'utf-8',
    })
      .pipe(csv.parse({ headers: false, delimiter: ';', skipRows: 1 }))
      .on('data', async (data) => {

        //... removed for brevity

        const checkDuplicateRes = await this.transactionService.checkDuplicate(
          amount,
          name,
          usage,
          bookingDate,
        );

        if (checkDuplicateRes.length === 0) {
          const labelId = await this.sortLabel(data);
          const newTransaction = {
            amount,
            name,
            usage,
            label_id: labelId,
            bankaccount_id: bankaccountId,
            booking_date: bookingDate,
            created_at: timestamp,
            updated_at: timestamp,
          };

          await this.transactionService.create(newTransaction);
          imports++;
        }
        const unsortedTransactions = await this.transactionService.getUnsorted();
        return response.send({ unsortedTransactions, imports });
      });

  }

这里我们基本上是用上面的语法替换.then 语法。如果您不熟悉,我建议您阅读它,因为它比链接 .then()s 更容易理解

【讨论】:

  • 嗨,詹姆斯,非常感谢您的帮助。但是,这为我产生了与以前相同的输出。第一次上传 CSV 文件时,再次返回 { "unsortedTransactions": [], "imports": 0 }。
  • 嗯,我假设您的数据库正在正确保存和获取记录?我建议检查那里的值。 imports: 0 仍然发生的事实看起来像您的 (checkDuplicateRes.length === 0) 失败了。这意味着该块中的任何内容都不会运行。你可能想研究这个函数this.transactionService.checkDuplicate(amount, name, usage, bookingDate)。因为这里的内容应该在(a)等待异步调用完成方面起作用。
  • 非常感谢您的帮助。我在没有 checkDuplicate 功能的情况下再次尝试了它。但是,它也不是那样工作的,数据被正确导入到数据库中,因此创建了条目。我认为是nestjs特有的,数据库操作是异步执行的,响应是从控制器返回的。
  • 您绝对可以等待数据库读取/写入。读取流回调中的所有内容吗?很难说,但您的 response.send 和语句也必须在回调 .on('data', (data) =&gt; {//here} 内,否则它们也将与读取流异步
  • 非常感谢您的帮助,问题已解决。在完全合乎逻辑的情况下。
猜你喜欢
  • 2021-11-23
  • 2021-09-04
  • 2019-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-20
  • 1970-01-01
  • 2019-05-22
相关资源
最近更新 更多