如何使用颤振和飞镖从 Cloud Firestore 检索特定数据?

Posted

技术标签:

【中文标题】如何使用颤振和飞镖从 Cloud Firestore 检索特定数据?【英文标题】:how to retrieve specific data from Cloud Firestore using flutter and dart? 【发布时间】:2020-05-12 20:29:36 【问题描述】:

我一直在阅读 *** 阅读相关的帖子。但是,我还没有找到一个简单的解决方案,对于像我这样的初学者来说很容易理解。目前,我的 Cloud Firestore 数据库如下所示:

在用户输入足够的信息以填充文档中的每个字段后(ID 是通过电话身份验证的经过身份验证的用户的 UID),然后将其发送到数据库中。之后,用户被重定向到应该显示这些字段中的每一个的主屏幕。这就是我卡住的地方。下面是一个我已经开始实现的方法,它将返回一个字符串,该字符串将位于 Text 小部件中,以显示在数据库中找到的用户名。

String getUsername(FirebaseUser user, Firestore firestore) 

    //get the document reference
    DocumentReference docReference = firestore.document("Users/" + user.uid);

    Future<DocumentSnapshot> snapshot = docReference.get();

    Stream<DocumentSnapshot> stream = snapshot.asStream();

    //stub to ignore compiler warnings
    return null;
 

如您所见,在使用 Futures 和 Streams 时,我相当迷茫。我在 youtube 上观看了 google flutter 开发人员的视频,他们帮助我达到了这一点。我还尝试使用 Future 对象提供的 then() 和 whenCompleted() 方法,但是我发现自己挖了一个越来越大的洞。

非常感谢所有帮助!

【问题讨论】:

这个“futures, async, await”文档是一个很好的起点:dart.dev/codelabs/async-await#what-is-a-future 此外,这个关于异步代码的简短视频提供了一个很好的概述:youtube.com/watch?v=nHsxIQ9KMn0 祝你好运! 【参考方案1】:

要获取用户信息,请尝试以下操作:

Future<DocumentSnapshot> getUserInfo()async
var firebaseUser = await FirebaseAuth.instance.currentUser();
return await Firestore.instance.collection("users").document(firebaseUser.uid).get();

然后在您的build() 方法中使用FutureBuilder

          FutureBuilder(
            future: getUserInfo(),
            builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) 
              if (snapshot.connectionState == ConnectionState.done) 
                return ListView.builder(
                    shrinkWrap: true,
                    itemCount: 1,
                    itemBuilder: (BuildContext context, int index) 
                      return ListTile(
                        title:
                            Text(snapshot.data.data["email"]),
                      );
                    );
               else if (snapshot.connectionState == ConnectionState.none) 
                return Text("No data");
              
              return CircularProgressIndicator();
            ,
          ),

在方法中使用await 时,该方法需要声明为async。此外,您需要返回一个Future,以便能够在屏幕上显示结果,然后您需要使用FutureBuilder 小部件。

https://dart.dev/codelabs/async-await

【讨论】:

【参考方案2】:

当您只需要获取一次数据时,您可以使用 Futures,例如:

final queryofdocs = await Firestore.instance.collection('Users').getDocuments()

此代码返回一个Future&lt;QuerySnapshot&gt;,其中包含该集合中的所有文档。 然后你可以尝试像这样获取一个文档:

final queryofonedocs = await Firestore.instance.document('users/uid').get()

这会返回一个Future&lt;DocumentSnapshot&gt;,其中包含该文档中的所有字段。

最后,您可以使用 Streams 监听数据变化。

final suscription = await Firestore.instance.collection('tasks').snapshots()

如果您更改某些数据并取消存储应用更新中的数据,这将返回 Stream&lt;QuerySnapshot&gt;

DocumentSnapshots 在文档中有信息字段,QuerySnapshotDocumentSnapshots 的集合。

希望对你有帮助

【讨论】:

【参考方案3】:

以下代码是null safe,并已更新为最新版本的库:

var collection = FirebaseFirestore.instance.collection('users');
  
FutureBuilder<DocumentSnapshot<Map<String, dynamic>>>(
  future: collection.doc('$user.uid').get(),
  builder: (_, snapshot) 
    if (snapshot.hasError) return Text('Error = $snapshot.error');
  
    if (snapshot.hasData) 
      var output = snapshot.data!.data();
      var value = output!['email']; // example@gmail.com
      return Text(value);
    
  
    return Center(child: CircularProgressIndicator());
  ,
);

【讨论】:

@Kamlesh 你需要使用我自己还没有尝试过的rxdart 包。 谢谢亲爱的@CopsOnRoad,我已经用过它了,但可能有些东西不见了或还没用。 @Kamlesh 不幸的是,我对此无能为力。对不起:(【参考方案4】:

这是我们如何做到这一点的过程

创建 AuthController 类

class AuthController extends GetxController 

  static AuthController to = Get.find();

  AppLocalizations_Labels labels;
  TextEditingController nameController = TextEditingController();
  TextEditingController emailController = TextEditingController();
  TextEditingController passwordController = TextEditingController();

  final FirebaseAuth _auth = FirebaseAuth.instance;
  final FirebaseFirestore _db = FirebaseFirestore.instance;

  Rx<User> firebaseUser = Rx<User>();
  Rx<UserModel> firestoreUser = Rx<UserModel>();
  final RxBool admin = false.obs;

  @override
  void onReady() async 
    //run every time auth state changes
    firebaseUser.value = await getUser;
    firebaseUser.bindStream(user);
    super.onReady();
  

  @override
  void onClose() 
    nameController?.dispose();
    emailController?.dispose();
    passwordController?.dispose();
    super.onClose();
  


  // Firebase user one-time fetch
  Future<User> get getUser async => _auth.currentUser;

  // Firebase user a realtime stream
  Stream<User> get user => _auth.authStateChanges();

  //Streams the firestore user from the firestore collection
  Stream<UserModel> streamFirestoreUser() 
    print('streamFirestoreUser()');
    if (firebaseUser?.value?.uid != null) 
      return _db
          .doc('/users/$firebaseUser.value.uid')
          .snapshots()
          .map((snapshot) => UserModel.fromMap(snapshot.data()));
    

    return null;
  

  //get the firestore user from the firestore collection
  Future<UserModel> getFirestoreUser() 
    if (firebaseUser?.value?.uid != null) 
      return _db.doc('/users/$firebaseUser.value.uid').get().then(
          (documentSnapshot) => UserModel.fromMap(documentSnapshot.data()));
    
    return null;
  

  //Method to handle user sign in using email and password
  signInWithEmailAndPassword(BuildContext context) async 
    final labels = AppLocalizations.of(context);
    showLoadingIndicator();
    try 
      await _auth.signInWithEmailAndPassword(
          email: emailController.text.trim(),
          password: passwordController.text.trim()
      );
      emailController.clear();
      passwordController.clear();
      hideLoadingIndicator();
     catch (error) 
      hideLoadingIndicator();
      Get.snackbar(labels.auth.signInErrorTitle, labels.auth.signInError,
          snackPosition: SnackPosition.BOTTOM,
          duration: Duration(seconds: 7),
          backgroundColor: Get.theme.snackBarTheme.backgroundColor,
          colorText: Get.theme.snackBarTheme.actionTextColor);
    
  


创建 userInfo 类,通过 GetBuilder 显示用户数据

class UserInfo extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    final labels = AppLocalizations.of(context);

    return GetBuilder<AuthController>(
      init: AuthController(),
      builder: (controller) => controller?.firestoreUser?.value?.uid == null
          ? Center(
              child: CircularProgressIndicator(),
            )
          : Scaffold(
              appBar: AppBar(
                title: Text(labels?.home?.title),
                actions: [
                  IconButton(
                      icon: Icon(Icons.settings),
                      onPressed: () 
                        Get.to(SettingsUI());
                      ),
                ],
              ),
              body: Center(
                child: Column(
                  children: <Widget>[
                    SizedBox(height: 120),
                    Avatar(controller.firestoreUser.value),
                    Column(
                      mainAxisAlignment: MainAxisAlignment.start,
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: <Widget>[
                        FormVerticalSpace(),
                        Text(
                            labels.home.uidLabel +
                                ': ' +
                                controller.firestoreUser.value.uid,
                            style: TextStyle(fontSize: 16)),
                        FormVerticalSpace(),
                        Text(
                            labels.home.nameLabel +
                                ': ' +
                                controller.firestoreUser.value.name,
                            style: TextStyle(fontSize: 16)),
                        FormVerticalSpace(),
                        Text(
                            labels.home.emailLabel +
                                ': ' +
                                controller.firestoreUser.value.email,
                            style: TextStyle(fontSize: 16)),
                        FormVerticalSpace(),
                        Text(
                            labels.home.adminUserLabel +
                                ': ' +
                                controller.admin.value.toString(),
                            style: TextStyle(fontSize: 16)),
                      ],
                    ),
                  ],
                ),
              ),
            ),
    );
  

【讨论】:

以上是关于如何使用颤振和飞镖从 Cloud Firestore 检索特定数据?的主要内容,如果未能解决你的问题,请参考以下文章

构建颤振项目时如何将飞镖和颤振设置为默认值

你如何在颤振飞镖中渲染脚本标签

如何取消颤振/飞镖集团中的“等待”

如何在颤振(飞镖)应用程序和 PHP 网站之间使用 SALT+HASH 密码保存/检查?

如何在颤振/飞镖扩展中禁用蓝色警告下划线标志?

如何在 Xcode macosx 中安装颤振和飞镖?