将文档数据检索到一个列表中,其中 documentID 与 currentUser().uid 相同 - Flutter

Posted

技术标签:

【中文标题】将文档数据检索到一个列表中,其中 documentID 与 currentUser().uid 相同 - Flutter【英文标题】:Retrieving documents data into a List where documentID is the same as currentUser().uid - Flutter 【发布时间】:2021-01-18 03:14:35 【问题描述】:

我的 CustomerNotifier 类中有一个函数,它从 Firebase 中读取所有客户作为列表,如下所示:

  getCustomers(CustomerNotifier customerNotifier) async 
    String userId = (await FirebaseAuth.instance.currentUser()).uid;

    print('Current logged in user uid is: $userId');

    var snapshot = await customerCollection
        .orderBy('created_at', descending: true)
        .getDocuments();

    List<Customer> _customerList = [];

    snapshot.documents.forEach((document) 
      Customer customer = Customer.fromMap(document.data);
      _customerList.add(customer);
    );

    customerNotifier.customerList = _customerList;
  

我有另一个功能来更新或创建新客户并保存到 Firebase,如下所示:

Future updateCustomer(Customer customer, bool isUpdating) async 
    CollectionReference customerRef =
        await Firestore.instance.collection('customer');
    if (isUpdating) 
      customer.updatedAt = Timestamp.now();
      await customerRef.document().updateData(customer.toMap());
      print('updated customer with id: $customer.id');
     else 
      customer.createdAt = Timestamp.now();

      DocumentReference documentReference =
          await customerRef.add(customer.toMap());

      customer.id = documentReference.documentID;

      print('created customer successfully with id: $customer.id');

      await documentReference.setData(customer.toMap(), merge: true);
      addCustomer(customer);
    
    notifyListeners();
  

通过上述两种方法,我曾经成功地读取客户数据并将其写入我的 Firebase。但是,我试图只读取当前登录用户创建和更新的数据。所以来自其他***线程的建议,我被建议将我的customer.id设置为userId,其中userId == currentUser().uid。我可以使用更新版本的 updateCustomer 成功写入我的数据库,如下所示:

Future updateCustomer(Customer customer, bool isUpdating) async 
    CollectionReference customerRef =
        await Firestore.instance.collection('customer');
    FirebaseUser user = await FirebaseAuth.instance.currentUser();
    String userId = user.uid;
    print('Current logged in user uid is: $userId');

    if (isUpdating) 
      customer.updatedAt = Timestamp.now();
      await customerRef.document(userId).updateData(customer.toMap());
      print('updated customer with id: $customer.id');
     else 
      customer.createdAt = Timestamp.now();

      DocumentReference documentReference = await customerRef.document(userId);
      // add(customer.toMap());

      customer.id = documentReference.documentID;

      print('created customer successfully with id: $customer.id');

      await documentReference.setData(customer.toMap(), merge: true);
      addCustomer(customer);
    
    notifyListeners();
  

我如何继续从仅由 currentUser() 创建的 firebase 读取客户数据,因为 documentID/customer.id 现在等于 currentUser() 登录的 userId?


这是我迄今为止尝试过的:

  getCustomers(CustomerNotifier customerNotifier) async 
String userId = (await FirebaseAuth.instance.currentUser()).uid;

print('Current logged in user uid is: $userId');

QuerySnapshot snapshot = await Firestore.instance
    .collection('customers')
    .where('id', isEqualTo: userId)
    .orderBy('created_at', descending: true)
    .getDocuments();

List<Customer> _customerList = [];

snapshot.documents.forEach((document) 
  Customer customer = Customer.fromMap(document.data);
  _customerList.add(customer);
);

customerNotifier.customerList = _customerList;

//customer_screen.dart //这使用一个ListView.builder来显示currentUser()创建的所有客户

class CustomersScreen extends StatefulWidget 
  static String id = 'customers';
    
  @override
  _CustomersScreenState createState() => _CustomersScreenState();

    
class _CustomersScreenState extends State<CustomersScreen> 

  bool showSpinner = true;
  bool _isInit = true;

  @override
  void initState() 
    if (_isInit) 
      showSpinner = true;
     else 
      showSpinner = false;
    
    CustomerNotifier customerNotifier =
        Provider.of<CustomerNotifier>(context, listen: false);
    customerNotifier.getCustomers(customerNotifier);
    super.initState();
  

  @override
  Widget build(BuildContext context) 
    CustomerNotifier customerNotifier = Provider.of<CustomerNotifier>(context);

    Future<void> _resfreshList() async 
      customerNotifier.getCustomers(customerNotifier);
    

    return Scaffold(
      drawer: DrawerClass(),
      appBar: AppBar(
        title: Text(
          'All customers',
          style: kAppBarTextStyle,
        ),
        backgroundColor: kAppBarColour,
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () 
          customerNotifier.currentCustomer = null;
          Navigator.of(context)
              .push(MaterialPageRoute(builder: (BuildContext context) 
            return CustomerFormScreen(isUpdating: false);
          ));
        ,
        child: Icon(Icons.add),
        backgroundColor: kThemeIconColour,
      ),
      // body: showSpinner
      //     ? Center(child: CircularProgressIndicator())
      body: RefreshIndicator(
        child: Consumer<CustomerNotifier>(
          builder: (context, customer, child) 
            return customer == null
                ? Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      PaddingClass(bodyImage: 'images/empty.png'),
                      SizedBox(
                        height: 20.0,
                      ),
                      Text(
                        'You don\'t have any customer',
                        style: kLabelTextStyle,
                      ),
                    ],
                  )
                : Padding(
                    padding: const EdgeInsets.only(top: 50.0),
                    child: ListView.separated(
                      itemBuilder: (context, int index) 
                        return Card(
                          margin: EdgeInsets.fromLTRB(20.0, 0.0, 20.0, 0.0),
                          elevation: 15.0,
                          color: Colors.white70,
                          child: Row(
                            crossAxisAlignment: CrossAxisAlignment.center,
                            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                            children: <Widget>[
                              Container(
                                height: 100.0,
                                child: Icon(
                                  FontAwesomeIcons.userCircle,
                                  color: kThemeIconColour,
                                  size: 50.0,
                                ),
                              ),
                              SizedBox(width: 20.0),
                              Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                mainAxisAlignment: MainAxisAlignment.center,
                                children: <Widget>[
                                  Text(' $customer.customerList[index].firstName' +
                                      '  $customer.customerList[index].lastName'),
                                  SizedBox(
                                    height: 8.0,
                                  ),
                                  Text(
                                      ' $customer.customerList[index].phoneNumber'),
                                  SizedBox(
                                    height: 8.0,
                                  ),
                                  Text(
                                      ' $customer.customerList[index].email'),
                                ],
                              ),
                              GestureDetector(
                                onTap: () 
                                  customerNotifier.currentCustomer =
                                      customerNotifier.customerList[index];
                                  Navigator.of(context).push(MaterialPageRoute(
                                      builder: (BuildContext context) 
                                    return CustomerDetailsScreen();
                                  ));
                                ,
                                child: Icon(
                                  FontAwesomeIcons.caretDown,
                                  color: kThemeIconColour,
                                ),
                              ),
                            ],
                          ),
                        );
                      ,
                      separatorBuilder: (BuildContext context, int index) 
                        return SizedBox(
                          height: 20.0,
                        );
                      ,
                      itemCount: customerNotifier.customerList.length,
                    ),
                  );
          ,
        ),
        onRefresh: _resfreshList,
      ),
    );
  

谢谢。

【问题讨论】:

您可以发布您当前尝试检索单个客户数据的代码吗? 我刚刚发布了我尝试过的内容。 我在这里看到的是您有一个名为 Users 的集合,该集合中的文档由 uid 命名。您是否只想获取单个 uid 的信息?如果是这样,那么您希望使用 documentSnapshot。但是,您的函数看起来正在寻找客户的集合 -> 这意味着您可能需要第二个集合,因此它看起来像:客户(集合)-> uid(文档)-> thisUsersItems(集合)跨度> 我正在寻找一系列客户。所以基本上,当前登录用户创建的所有客户。我已经将每个客户文档的 documentId 设置为与 currentUser() uid 相同。我不确定我是否得到你最后评论的后半部分。你能用一个示例/更多解释来解释吗?谢谢。 好的,有道理!执行此操作的方法不止一种,您已根据客户文档中的值选择执行此操作。让我更新我的答案 【参考方案1】:

EDIT2: 在此处查看复合查询:https://firebase.google.com/docs/firestore/query-data/queries

特别是本节:

db.collection("cities").where("capital", "==", true)
    .get()
    .then(function(querySnapshot) 
        querySnapshot.forEach(function(doc) 
            // doc.data() is never undefined for query doc snapshots
            console.log(doc.id, " => ", doc.data());
        );
    )
    .catch(function(error) 
        console.log("Error getting documents: ", error);
    );

你可以使用这个结构。 'cities' 对您来说是 'customer',而“capital” 是您保存为 userIdWhenYouCreatedThisCustomerDocument 的文档中的字段,而不是 true,您将输入当前的用户 ID。当然,这使用 .then(),您可以这样做或使用 await 将结果分配给变量。

我会注意,您应该在完成此操作时查看文档,特别是考虑到以这种方式执行此操作与按用户 ID 执行子集合。两者都是正确的,但是如果您超越概念证明,您会发现 firestore 中的“where 子句不是过滤器”短语是考虑后一种方法的理由。当然,这最终可能根本不重要。


编辑: 基于新信息

您为什么使用 QuerySnapshot?您(当前)正在为此检索文档快照,因此您可以直接使用它。

或者,您能否发布您的 Firestore 的屏幕截图,并删除敏感数据?我想知道您是否打算将数据存储在用户文档中,例如即时检索查询代码期望编写的内容和您的 upsert 代码交付,而不是将其存储在用户文档中的集合中。 如果是后者,另一个答案中的代码可能对您和您当前的代码更有效,因为它被设置为从集合中读取,而不是从文档中读取。当然,任何一种方法都可以同样有效。问题是,现在您的 upsert 和查询的前半部分正在执行前者,而在检索查询的中途您切换到后者。


我认为您可以将其他问题 (Read data from Firebase created by loggedin user - Flutter) 的答案与文档结合起来,在此处找到您的解决方案。

这使用的 firestore 版本比您正在使用的版本更新,但提供了一个很好的起点。 https://firebase.google.com/docs/firestore/query-data/get-data

例如。

    DocumentReference ref =
    Firestore.instance.collection('YourCollectionNameInFireStore').document(user.uid);
    var temp = await docRef.getDocument();
    // do something with the data if you want.. not sure of syntax for old version on 
    // this, for new version it is .data()
    temp.data.<field>

【讨论】:

嗨,斯科特。我刚刚在上面的问题中添加了我的 Firestore 的屏幕截图。 嗨,苏格兰人。我听从了您的建议,还通读了文档以了解其工作原理。我能够写信给 firebase,但似乎我在 READ/getCustomers 中缺少一些东西。我在我的问题中编辑了我的 getCustomers() 函数以反映我当前的实现。它第一次工作,但一旦我刷新/热重启应用程序,我就无法在我的 Listview 屏幕中查看所有客户。 嘿。好的,当然,如果不在那里进行讨论,仍然很难确切地知道发生了什么!但是,如果您说 getCustomers 可以满足您的需求,那听起来像是进步。现在可能需要在问题正文中向我们展示您调用该函数的位置。例如,它是否在构建中? 是的。我已经粘贴了我的 customer-screen.dart 代码。这是我调用 getCustomers() 以显示 customer.id == userId 的所有客户的列表的屏幕。也许这提供了更多的上下文。 我读得很快,我自己并没有使用过 onRefresh,但我想知道同时使用 Consumer 和 refresh 来修改 CustomerNotifier,该 CustomerNotifier 每次构建都会重新构建并可以互换使用。 child: Consumer( builder: (context, customer, child) 有你之后使用的“customer”。但是,你的 onRefresh 正在更新“customerNotifier”:CustomerNotifier customerNotifier = Provider.of(context); Future _resfreshList() async customerNotifier.getCustomers(customerNotifier);

以上是关于将文档数据检索到一个列表中,其中 documentID 与 currentUser().uid 相同 - Flutter的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Firestore 中获取生成的文档 ID,然后将子集合添加到其中?

FCM 到多个设备(令牌)列表

mongoDB-document

如何将Excel导入到SharePoint列表

PDF Document文件如何复制到Word文档编辑

如何在使用模板的 word 文档中创建下拉列表?