遍历Firestore集合中的总和值的文档的最佳方法是什么?

时间:2018-10-09 21:20:52

标签: firebase flutter google-cloud-firestore

我正在尝试使用Flutter的“ cloud_firestore”包找出如何对存储在Firestore集合中每个文档上的值求和。

我尝试了以下代码:

double queryValues() {
    total = 0.0;

    Firestore.instance
        .collection('myCollection')
        .snapshots()
        .listen((snapshot) {
        snapshot.documents.forEach((doc) => this.total += 
                                            doc.data['amount']);
    });
    debugPrint(this.total.toString());
    return total;
  }

但是我最终将结果打印为0.0。如果删除第一行(总计= 0.0。),则总和有效,但如果重新加载,则值将增加一倍(总计为原来的总数)。

我知道他们说最好的解决方案是在每次写文档时都使用Cloud Function存储此汇总值,但是这很痛苦,因为我想在某些范围内使总计可供用户查询(月,年,周)。这些查询产生的文档数量很少,所以对我来说,仅迭代结果集合是理想的选择。

这是我发布的第一个问题,对此我深表感谢。

3 个答案:

答案 0 :(得分:1)

如果您正在使用异步函数,则可以在listen()方法内完成所有工作,或者在方法外等待,直到您确定内部所有操作都已完成。

处理第二种情况的“颤动”方法是使用setState()。您build()使用具有初始外部值的窗口小部件树,并且当异步函数完成时,您调用setState(),以便使用新值重建窗口小部件树。

(请注意,在异步功能内,您可以使用在上一个操作上累积的fold()列表方法。)

这是一个完整的简单应用,将使用外部总价值:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  double total = 0.0;

  @override
  initState() {
    super.initState();
    queryValues();
  }

  void queryValues() {
    Firestore.instance
        .collection('myCollection')
        .snapshots()
        .listen((snapshot) {
      double tempTotal = snapshot.documents.fold(0, (tot, doc) => tot + doc.data['amount']);
      setState(() {total = tempTotal;});
      debugPrint(total.toString());
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(child: Text("Total: $total")),
    );
  }
}

答案 1 :(得分:0)

正如Doug所说,数据是从Firestore异步加载的。到您打印总和时,尚未加载数据,forEach还没有运行,并且总数仍为0.0

通过放置一些打印语句,最容易看到正在发生的事情:

print("Before calling listen");
Firestore.instance
    .collection('myCollection')
    .snapshots()
    .documents((snapshot) {
      print("Got data");
    }
print("After calling listen");

运行此代码时,它会打印:

  

在调用监听之前

     

拨打电话后

     

获得数据

这可能不是您期望的顺序。但这解释了为什么没有结果和总和0.0:数据尚未加载。

要解决此问题,您需要使用Dart的async / await关键字。

double queryValues() async {
  total = 0.0;

  docs = await Firestore.instance
    .collection('myCollection')
    .snapshots()
    .documents((snapshot);
  docs.forEach((doc) => this.total += doc.data['amount']));
  debugPrint(this.total.toString());
  return total;
}

您会注意到,我也用listen()替换了get(),因为您只想获取一次文档(listen()将保持活动状态,这意味着您无法返回结果)。

然后调用:

sum = await queryValues();
print(sum)

答案 2 :(得分:0)

 CollectionReference _documentRef=Firestore.instance.collection("User");

   _documentRef.getDocuments().then((ds){
     if(ds!=null){
            ds.documents.forEach((value){
              print(value.data);
            });
     }
   });