Flutter中如何对比Firestore时间戳与当前日期并汇总当日消费
汇总Firestore中当日消费总金额的实现方案
一、最优方案:使用Firestore原生Timestamp类型存储时间
把时间存为字符串会导致查询效率低下,还容易出现时区、格式匹配问题,建议直接存储Firestore的Timestamp类型:
1. 修改写入代码
将原代码中的timestampday字段改为直接存储Timestamp.now(),无需转成字符串:
Future<void> addGood( String good, client, int amount, double price, String username) { return goods.add({ 'good': good, 'amount': amount, 'price': price, 'client': client, 'username': currentUser!.email, 'timestampday': Timestamp.now() // 直接存Timestamp类型 }); }
2. 当日消费汇总查询
计算当日的起始和结束时间戳,通过where过滤出当日的文档,再遍历求和:
Future<double> getTodayTotalSpending() async { // 获取当前日期的起始时间(本地时区的00:00:00) final now = DateTime.now(); final startOfDay = DateTime(now.year, now.month, now.day); // 当日结束时间(次日00:00:00) final endOfDay = startOfDay.add(const Duration(days: 1)); // 转换为Firestore Timestamp final startTimestamp = Timestamp.fromDate(startOfDay); final endTimestamp = Timestamp.fromDate(endOfDay); // 查询当日的消费记录 final querySnapshot = await goods .where('timestampday', isGreaterThanOrEqualTo: startTimestamp) .where('timestampday', isLessThan: endTimestamp) .get(); // 汇总总金额 double total = 0; for (var doc in querySnapshot.docs) { total += doc.data()['price'] as double; } return total; }
这种方式利用Firestore的索引优化查询,效率远高于字符串匹配。
二、兼容现有字符串格式的处理方案
如果已经将时间存为字符串(比如DateTime.toString()输出的"yyyy-MM-dd HH:mm:ss.SSS"格式),可以通过前缀匹配查询当日数据:
Future<double> getTodayTotalSpendingWithStringTimestamp() async { final now = DateTime.now(); // 获取当日日期的字符串前缀,比如"2024-06-12" final todayDateStr = "${now.year}-${now.month.toString().padLeft(2, '0')}-${now.day.toString().padLeft(2, '0')}"; // 查询timestampday以当日日期前缀开头的文档 final querySnapshot = await goods .where('timestampday', isGreaterThanOrEqualTo: todayDateStr) .where('timestampday', isLessThan: "${todayDateStr}z") // 利用字符串排序特性,"z"大于所有时间字符 .get(); // 汇总总金额 double total = 0; for (var doc in querySnapshot.docs) { total += doc.data()['price'] as double; } return total; }
注意:这种字符串前缀查询无法利用Firestore的高效索引,当数据量较大时性能会明显下降,建议逐步将现有字符串时间字段迁移为
Timestamp类型。
内容的提问来源于stack exchange,提问作者1rre7
相关产品推荐
相关产品推荐

