You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB统计实现:计算待支付总金额与uploadedAt到paidAt平均间隔

解决方案

方案1:使用MongoDB聚合查询(推荐,数据量大时性能更好)

你之前的聚合查询缺少两个核心部分:过滤条件和待支付金额统计,调整后的代码如下:
首先要把findAll里的过滤规则同步到聚合的$match阶段,保证和原有查询权限、软删除规则一致:

// 先拼接过滤条件,和findAll逻辑对齐
const baseCriteria = {
  company: company._id,
  deleted: { $ne: true }
};
// 拼接权限过滤条件(如果有ability实例的话)
let matchCriteria = baseCriteria;
if (ability) {
  ability.throwUnlessCan('read', this.invoiceModel.modelName);
  matchCriteria = {
    ...toMongoQuery(ability, this.invoiceModel.modelName),
    ...matchCriteria
  };
}

const stats = await this.invoiceModel.aggregate([
  // 第一步:过滤符合条件的发票,和原有查询逻辑一致
  { $match: matchCriteria },
  // 第二步:分组统计,_id设为null表示统计所有符合条件的记录
  {
    $group: {
      _id: null,
      // 统计待支付总金额:单条预期金额-已付金额,再求和
      totalOutstanding: {
        $sum: { $subtract: ["$amount.expected", "$amount.paid"] }
      },
      // 统计平均支付间隔,仅计算已付款(paidAt不为空)的记录
      averagePaymentIntervalMs: {
        $avg: {
          $cond: {
            if: { $ne: ["$paidAt", null] },
            then: { $subtract: ["$paidAt", "$uploadedAt"] },
            else: "$$REMOVE" // 未付款的记录不参与平均计算
          }
        }
      },
      // 可选:统计总发票数、已付款发票数方便校验结果
      totalInvoices: { $sum: 1 },
      paidInvoices: {
        $sum: { $cond: [{ $ne: ["$paidAt", null] }, 1, 0] }
      }
    }
  }
]);

// 处理返回结果
const result = stats[0] || {
  totalOutstanding: 0,
  averagePaymentIntervalMs: 0,
  totalInvoices: 0,
  paidInvoices: 0
};
// 可按需转换毫秒为天/小时,比如转天数:
const averagePaymentDays = result.averagePaymentIntervalMs / (1000 * 60 * 60 * 24);

如果你需要按账户分组统计,只需要把$group的_id改为_id: "$account"即可。

方案2:基于现有findAll查询结果计算(适合数据量小的场景)

如果你的发票数据量不大,也可以直接复用已有的findAll方法,拿到结果后在应用层计算:

const invoiceParams = new FindParams();
invoiceParams.criteria = { company: company._id };
// 只查需要的字段,减少不必要的数据传输
invoiceParams.select = 'amount paidAt uploadedAt';

const invoices = await this.findAll(invoiceParams);

let totalOutstanding = 0;
let totalIntervalMs = 0;
let paidCount = 0;

for (const invoice of invoices) {
  // 累加待支付金额
  totalOutstanding += invoice.amount.expected - invoice.amount.paid;
  // 计算已付款记录的日期间隔
  if (invoice.paidAt) {
    totalIntervalMs += new Date(invoice.paidAt).getTime() - new Date(invoice.uploadedAt).getTime();
    paidCount++;
  }
}

const averagePaymentIntervalMs = paidCount > 0 ? totalIntervalMs / paidCount : 0;
const averagePaymentDays = averagePaymentIntervalMs / (1000 * 60 * 60 * 24);

注意事项

  • 你的示例数据里paidAt字段少写了一个闭合引号,实际业务代码中要避免这类语法错误
  • 如果存在未付款的发票,记得在计算平均间隔时排除这类记录,避免统计结果失真
  • 若金额字段存在小数,可根据业务需求添加$round做精度处理

内容的提问来源于stack exchange,提问作者CashServices

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 18:06:00