You need to enable JavaScript to run this app. 如何对对象数组实现open状态优先前置、再按创建时间二级排序
优惠活动
大模型
产品
解决方案
定价
更多

如何对对象数组实现open状态优先前置、再按创建时间二级排序

多规则排序实现与代码问题修复

问题根源定位

你的代码拿不到正确排序结果,本质上不是排序逻辑写错了,而是异步执行时序错位导致你在数据完全加载前就执行了排序,叠加排序规则缺失,才会完全达不到预期效果,具体拆解:

  • 时序问题:Firestore的collection.get()是返回Promise的异步操作,原代码在最外层db.get().then()回调还没走完的位置,就同步执行了invoices.sort()、return操作,此时invoices数组从头到尾都是空的,不管你怎么写排序比较逻辑,结果都不会有任何变化。同时原代码嵌套的子集合发票查询没有统一的等待机制,子查询未完成时外层就提前退出执行,进一步放大了时序错位的问题。
  • 排序规则缺失:原有的排序逻辑只实现了“open状态优先排前”的分组规则,同状态分组下没有追加created字段的比较分支,自然没法实现二次排序。
  • 冗余实现:你之前尝试的Object.values(obj).includes("open")属于过度设计,我们明确知道状态存储在status字段上,直接读取该字段做判断即可,遍历整个对象值匹配的写法既增加性能消耗,还容易误匹配其他字段的文本值。

正确实现方案

调整点说明

  1. 用async/await重构异步流程,收集所有嵌套查询的Promise,等所有发票数据完全加载进数组后,再执行排序操作
  2. 补全两层排序的比较逻辑:
    • 第一优先级:先对比状态,open状态的发票排在非open状态前面
    • 第二优先级:同一状态分组内,按created字段时间倒序排列(最新创建的发票在前)
  3. 兼容Firestore的Timestamp类型created字段,避免直接运算报错

修正后的完整代码

export const fetchInvoices = async function (firestore, currentUser) {
    const db = firestore
        .collection("customers")
        .doc(currentUser)
        .collection("subscriptions");
    const invoices = [];
    // 等待所有订阅文档加载完成
    const subscriptionSnapshot = await db.get();
    // 收集每个订阅下的发票查询Promise,一次性等待所有查询完成
    const invoiceRequests = subscriptionSnapshot.docs.map(subDoc => 
        subDoc.ref.collection("invoices").get()
    );
    const invoiceSnapshots = await Promise.all(invoiceRequests);
    // 遍历所有发票快照填充数组
    invoiceSnapshots.forEach(snapshot => {
        snapshot.forEach(doc => {
            const data = doc.data();
            invoices.push({
                billing_reason: data.billing_reason,
                created: data.created,
                currency: data.currency,
                hosted_invoice_url: data.hosted_invoice_url,
                id: doc.id,
                invoice_id: doc.id,
                invoice_pdf: data.invoice_pdf,
                number: data.number,
                period_end: data.period_end,
                period_start: data.period_start,
                status: data.status,
                subtotal: data.subtotal,
                total: data.total
            });
        })
    });
    // 多规则排序
    const sortedInvoices = invoices.sort((a, b) => {
        // 第一优先级:open状态优先
        const statusRank = (b.status === 'open') - (a.status === 'open');
        if (statusRank !== 0) return statusRank;
        // 第二优先级:同状态下按创建时间倒序
        const getCreatedTime = (timeVal) => {
            // 兼容Firestore Timestamp 类型、数值时间戳两种格式
            if (typeof timeVal === 'number') return timeVal;
            return timeVal?.toMillis?.() ?? 0;
        }
        const timeA = getCreatedTime(a.created);
        const timeB = getCreatedTime(b.created);
        return timeB - timeA;
    });
    return sortedInvoices;
}

调用注意事项

因为函数本身改成了异步实现,调用fetchInvoices的时候必须搭配await关键字获取结果,不能直接同步读取返回值,否则拿到的还是Promise实例,不是实际的发票数组。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.01 11:06:05