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

React+Firestore日志应用:现有数据结构能否满足查询需求?

现有数据库结构完全可以实现你的需求,以下是具体实现方案

1. 按不同字段排序

Firestore的查询要求过滤条件(where)与排序字段(orderBy)的组合必须有对应的复合索引,你需要针对uid与每个排序字段的组合创建索引:

  • 按技能排序:
    查询代码:

    const skillSortedQuery = query(
      collection(db, 'logs'),
      where('uid', '==', user?.uid),
      orderBy('skill', 'asc') // 或 'desc'
    );
    

    需要在Firestore控制台创建复合索引:uid(升序/降序) + skill(对应排序方向)

  • 按创建日期排序:
    你当前的查询已经实现,对应的复合索引(uid + createdAt)应该已经自动生成(如果没有,Firestore会在控制台提示你创建)。

  • 按学习时长排序:
    由于日志里的时长分为hours和minutes,直接排序会有逻辑问题,建议先统一为总分钟数:

    • 方案一(推荐):写入日志时新增totalMinutes字段(计算方式:hours * 60 + minutes),之后直接按该字段排序:
      const durationSortedQuery = query(
        collection(db, 'logs'),
        where('uid', '==', user?.uid),
        orderBy('totalMinutes', 'desc') // 或 'asc'
      );
      
      需要创建复合索引:uid + totalMinutes
    • 方案二:获取所有日志后在前端计算总时长再排序,但数据量大时性能较差,且分页场景下无法正确排序。

2. 获取各技能的累计学习时长

有两种可行方案,根据你的数据量选择:

  • 前端统计(适合日志量较小的场景):
    获取用户所有日志后,用reduce累加各技能的时长:

    const userLogsSnapshot = await getDocs(logsRefQuery);
    const skillTotals = userLogsSnapshot.docs.reduce((acc, doc) => {
      const { skill, hours, minutes } = doc.data();
      if (!acc[skill]) {
        acc[skill] = { totalHours: 0, totalMinutes: 0 };
      }
      acc[skill].totalHours += hours;
      acc[skill].totalMinutes += minutes;
      // 统一整理时长格式(分钟转小时)
      if (acc[skill].totalMinutes >= 60) {
        acc[skill].totalHours += Math.floor(acc[skill].totalMinutes / 60);
        acc[skill].totalMinutes = acc[skill].totalMinutes % 60;
      }
      return acc;
    }, {});
    
  • Firestore聚合查询(适合日志量较大的场景):
    使用Firestore的聚合查询分组统计,需要确保已开启分组查询功能:

    const aggQuery = aggregateQuery(
      collection(db, 'logs'),
      where('uid', '==', user.uid),
      groupBy('skill'),
      sum('hours'),
      sum('minutes')
    );
    const aggSnapshot = await getAggregate(aggQuery);
    // 结果示例:{ groups: [{ skill: 'React', sum_hours: 5, sum_minutes: 30 }, ...] }
    

3. 获取某一天的累计学习时长

先构建当天的时间范围查询,再统计总时长:

步骤1:构建当天的时间范围

// 以当前日期为例,可替换为目标日期
const targetDate = new Date();
const startOfDay = new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate());
const endOfDay = new Date(startOfDay);
endOfDay.setDate(endOfDay.getDate() + 1);

步骤2:查询当天日志并统计

  • 前端统计:

    const dailyLogsQuery = query(
      collection(db, 'logs'),
      where('uid', '==', user.uid),
      where('createdAt', '>=', startOfDay),
      where('createdAt', '<', endOfDay)
    );
    const dailyLogsSnapshot = await getDocs(dailyLogsQuery);
    const dailyTotal = dailyLogsSnapshot.docs.reduce((acc, doc) => {
      acc.totalHours += doc.data().hours;
      acc.totalMinutes += doc.data().minutes;
      if (acc.totalMinutes >= 60) {
        acc.totalHours += Math.floor(acc.totalMinutes / 60);
        acc.totalMinutes = acc.totalMinutes % 60;
      }
      return acc;
    }, { totalHours: 0, totalMinutes: 0 });
    
  • 聚合查询:

    const dailyAggQuery = aggregateQuery(
      dailyLogsQuery,
      sum('hours'),
      sum('minutes')
    );
    const dailyAggSnapshot = await getAggregate(dailyAggQuery);
    const totalHours = dailyAggSnapshot.data().sum_hours;
    const totalMinutes = dailyAggSnapshot.data().sum_minutes;
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 05:34:53