FireBase FiRestore用于将文档与Textfield同步的原子事务

人气:846 发布:2022-10-16 标签: firebase flutter flutter-web dart google-cloud-firestore

问题描述

我是Firebase和FireStore的新手,在云FireStore中存储Textfield数据并对其执行事务时遇到问题,我怀疑我们是否可以执行更新事务,如果文档不存在,则它应该创建并执行事务...

我希望实现以下目标:

我要将当前用户uidemail存储在‘X’集合的文档中。

我想对‘X’集合的‘Y’(这里Y是uid/电子邮件)文档执行事务更新 此外,如果该用户的文档不存在,它应该创建一个文档,然后执行事务,然后如果用户在没有按下save按钮的情况下退出文本字段,则它应该从FireStore中删除。

我想传递用户的uid、title、tag、desc等。文档中的As字段(docID应为该当前用户的emailuser's uid)。

到目前为止,我能够从auth类获取用户,并使用initState()在我当前工作类中访问它,但我不知道如何获取uid/电子邮件并将其存储到‘X’集合文档

将数据传递给Firebase的代码为

 Future<void> postQ() async {
    FirebaseFirestore db = FirebaseFirestore.instance;
    CollectionReference question =
        FirebaseFirestore.instance.collection('question');
    DocumentReference cUser = question.doc(_currentUser.uid);
      // in the above line I tried to get currentuser uid but that also not working and below I want to pass title,etc... in the doc of that current user with fields title, tag, desc, users uid and email and docID should be the email or user's uid....
      await db.runTransaction((transaction) async {
      String title = title_Controller.text;
      String desc = desc_Controller.text;
      String tag = tag_Controller.text;
      DocumentReference qRef = db.collection('question').doc();
      DocumentSnapshot snapshot = await transaction.get(qRef);
      // int likesCount = snapshot.data['likes'];
      await transaction.update(qRef, {
        // 'authorId': _currentUser,
        'title': title,
        'desc': desc,
        'tag': tag,
      });
    });
  }
}

但它在代码上方向我抛出消息下方,那么如何在运行事务之前创建一条消息,且该文档应该将当前用户的uid和电子邮件作为一个字段。

无法对不存在的单据运行事务

下面是从终端中的文本字段获取不断更新的工作代码,

class CreateQ extends StatefulWidget {
  final User user;
  CreateQ({Key? key, required this.user}) : super(key: key);

  @override
  State<CreateQ> createState() => _CreateQState();
}

class _CreateQState extends State<CreateQ> {
  final title_Controller = TextEditingController();
  final desc_Controller = TextEditingController();
  final tag_Controller = TextEditingController();
  @override
  void initState() {
    super.initState();
    _currentUser = widget.user;
    super.initState();
    // Start listening to changes.
    title_Controller.addListener(_latestTitle);
    desc_Controller.addListener(_latestDesc);
    tag_Controller.addListener(_latestTag);
  }

  // @override
  // void dispose() {
  // Clean up the controller when the widget is removed from the widget tree.
  // This also removes the latestvalue listener.
  // title_Controller.dispose();
  // super.dispose();
  // }

  void _latestTitle() {
    print('Title text field: ${title_Controller.text}');
  }

  void _latestDesc() {
    print('Desc text field: ${desc_Controller.text}');
  }

  void _latestTag() {
    print('Tag text field: ${tag_Controller.text}');
  }

  // ignore: unused_field
  late User _currentUser;
  

  UploadTask? task;
  File? file;

  @override
  Widget build(BuildContext context) {
 body: Container(
          padding: EdgeInsets.all(32),
          child: ListView(shrinkWrap: true, children: [
            Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisAlignment: MainAxisAlignment.start,
              children: [
                TextField(
                  controller: title_Controller,
                  decoration: InputDecoration(
                      hintText: 'Your Title here',
                      counterText: '',
                      border: OutlineInputBorder()),
                  keyboardType: TextInputType.multiline,
                  maxLines: 1,
                  maxLength: 100,
                ),
                SizedBox(height: 8),
                TextField(
                  controller: desc_Controller,
                  decoration: InputDecoration(
                      hintText:
                          'Enter Your Description here... ',
                      border: OutlineInputBorder()),
                  keyboardType: TextInputType.multiline,
                  maxLines: 15,
                  maxLength: 10000,
                ),
                SizedBox(height: 8),
                TextField(
                  controller: tag_Controller,
                  decoration: InputDecoration(
                      hintText:
                          'Add up to 5 tags to describe what your question is about',
                      counterText: '',
                      border: OutlineInputBorder()),
                  keyboardType: TextInputType.text,
                  maxLines: 1,
                  maxLength: 100,
                ),  ));
  }
我尝试使用set()方法,但这引发了错误。如果有人能提供当前问题的工作样本,那将非常有帮助, 谢谢您...

推荐答案

如果文档不存在,则调用UPDATE不会创建文档。 如果文档不存在,SET将创建/更新文档。 但是,您可以检查文档是否存在,然后根据需要使用SET或UPDATE。

 DocumentSnapshot snapshot = await transaction.get(qRef);
if(snapshot.exists){
  //run update/set operation
}else{
 // run set operation
}

无论您是否使用事务,SET和UPDATE都将按照我上面提到的方式工作。事务处理使您能够在对任何一个文档的任何设置/更新失败时撤消任何文档操作。

您可以通过此处了解SET和UPDATE之间的区别。 https://firebase.google.com/docs/firestore/manage-data/add-data

360