Flutter Firestore读取所有文档

时间:2020-10-21 06:23:46

标签: flutter google-cloud-firestore

更新2

经过大量调试,我意识到在messages子集合中创建消息时会发生错误。在我写了聊天集合的子级Messages子集合之后,无论查询中有什么内容,它都会读取所有文档。我尝试了多种类型的查询,这些查询从一开始就可以使用,但是当我写入messages子集合时,它将读取所有文档,甚至包括我已经阅读的文档。

当我写到messages子集合时,我将批处理行注释掉,而仅在chats集合中显示最近的消息。再一次,这仅发生在发送消息的用户,现在是接收消息的用户。接收消息的用户将获得文档,当我重新进入聊天时,它不会调用所有文档。但是编写该msg并发送该消息的用户,以及该用户重新进入聊天室时,将读取所有文档,除非我不写到messages子集合,而只是更新chats集合。

代码:

  Future createChat({Chat chat, isCreating = false}) async => await Services().crud.batch(
        onBatch: (batch) {
          if (isCreating) {
            batch.set(
              APIs().chats.collection.doc(chat.chatID).collection(Constants.messages).doc(),
              chat.recentMessage.map(),
            );
            batch.set(
              APIs().chats.collection.doc(chat.chatID),
              chat.map(),
            );
          } else {
            batch.set(
              APIs().chats.collection.doc(chat.chatID).collection(Constants.messages).doc(),
              chat.recentMessage.map(),
            );
            batch.update(
              APIs().chats.collection.doc(chat.chatID),
              <String, dynamic>{
                'recentMessage': chat.recentMessage.map(),
                'updatedAt': chat.updatedAt,
              },
            );
          }
        },
        onSuccess: () => Funcs.log('Success'),
        onFailure: (e) => Funcs.log(e),
      );

我遇到了一个奇怪的问题,在我的聊天应用程序中,我有两个用户正在交谈,而在打开聊天页面时,它可以完美运行,实时收听传入消息,向上滚动以获取较旧的消息等。当我最初向用户发送消息时返回,然后返回到聊天列表页面,然后返回到Firestore读取并显示集合中的所有消息的聊天。但是在其他用户方面,当他收到一条消息后,没有响应就回去,然后又回到聊天室,这是正常的,没有任何奇怪的事情发生,直到我先发送一条消息然后回去然后再进入,然后其他用户集合中的所有消息。我还注意到,当用户接收到一条消息时,聊天流被调用一次,但是当用户发送一条消息时,则聊天呼叫倍增...

我设置的方式是,我正在侦听收到最新消息后添加的最新文档,如果没有以前的消息,则仅侦听传入的消息。当用户发送消息并发送后,然后通过Cloud Functions发送通知。 didComplete: true是Cloud Functions的回报。 MOD是修改的缩写,在聊天流中有修改的聊天记录。

再次说明一下,问题发生在用户发送消息,关闭聊天页面,再次打开聊天页面,然后即使有查询在哪里阅读时,集合中的所有文档也被读取在上一次阅读文档之后...因此,当我应该只阅读新文档时,它对所有先前文档的阅读方式对我来说甚至都没有意义。

代码-messages_list.dart

  // ignore: cancel_subscriptions
  StreamSubscription _streamSubscription;
  bool _isFetching = false;
  bool _didFetch = false;

  @override
  void initState() {
    Funcs.log(widget.chat.messages.map((e) => e.msg).toList());

    widget.chat.messages.isEmpty
        ? this._moreMessages().then((value) {
            this._initMessages();
            widget.scrollToBtm();
          })
        : this._initMessages();

    super.initState();
  }

  @override
  void dispose() {
    this._streamSubscription.cancel();
    super.dispose();
  }

  _initMessages() {
    Funcs.log('Init Live Messages...');

    var q;

    widget.chat.messages.isEmpty
        ? q = APIs().chats.collection.doc(widget.chat.chatID).collection('messages').orderBy('createdAt', descending: false)
        : q = APIs()
            .chats
            .collection
            .doc(widget.chat.chatID)
            .collection('messages')
            .orderBy('createdAt', descending: false)
            .startAfterDocument(widget.chat.messages.last.ds);

    this._streamSubscription = q.snapshots().listen((event) {
      event.docChanges.forEach((element) {
        Message m = Message.model(ds: element.doc, id: element.doc.id, map: element.doc.data());

        Funcs.log('READ ${m.msg}');

        if (mounted)
          setState(() {
            if (element.type == DocumentChangeType.added) {
              widget.chat.messages.add(m);
              widget.chat.messages.sort((a, b) => a.createdAt.compareTo(b.createdAt));
            }

            if (element.type == DocumentChangeType.modified) {
              int index = widget.chat.messages.indexOf(m);

              if (index >= 0) {
                widget.chat.messages[index] = m;
                widget.chat.messages.sort((a, b) => a.createdAt.compareTo(b.createdAt));
              }
            }

            if (element.type == DocumentChangeType.removed) {
              widget.chat.messages.remove(m);
              widget.chat.messages.sort((a, b) => a.createdAt.compareTo(b.createdAt));
            }
          });
        Funcs.log(widget.chat.messages.map((e) => e.msg).toList());
      });
    });
  }

  Future _moreMessages() async {
    if (!this._isFetching && !this._didFetch) {
      setState(() => this._isFetching = true);
      List<Message> messages;

      if (widget.chat.messages.isEmpty) {
        Funcs.log('Getting Messages...');
        messages = await APIs().chats.initMessages(chat: widget.chat);
        Funcs.log(messages.map((e) => e.msg).toList());
      } else {
        Funcs.log('Getting More Messages...');
        messages = await APIs().chats.moreMessages(chat: widget.chat);
        Funcs.log(messages.map((e) => e.msg).toList());
      }

      if (messages != null) {
        int oldCount = widget.chat.messages.length;
        widget.chat.messages.addAll(messages);
        widget.chat.messages.sort((a, b) => a.createdAt.compareTo(b.createdAt));
        int newCount = widget.chat.messages.length;

        if (oldCount != newCount) {
        } else {
          this._didFetch = true;
        }
        setState(() => this._isFetching = false);
      }

      Funcs.log('Getting Messages Complete.');
    }
  }

chat_page.dart

  Chat _chat;

  @override
  void initState() {
    this._chat = widget.chat;

    super.initState();
  }


  Widget _column() => Column(
        children: <Widget>[
          this._chat != null
              ? MessagesList(
                  controller: this._scrollController,
                  isReversed: false,
                  chat: this._chat,
                  scrollToBtm: this._scrollToBtm,
                )
              : Expanded(
                  child: Container(),
                ),
          Container(
            color: Colors.black,
            height: 1.0,
          ),
          Container(
            height: 45.0,
            decoration: BoxDecoration(),
            margin: EdgeInsets.only(left: 15.0, right: 15.0, bottom: 15.0),
            child: Column(
              children: <Widget>[
                Expanded(
                  child: Row(
                    crossAxisAlignment: CrossAxisAlignment.center,
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      Expanded(
                        child: Padding(
                          padding: EdgeInsets.only(right: 15.0),
                          child: Directionality(
                            textDirection: TextDirection.ltr,
                            child: TextField(
                              controller: this._msgTEC,
                              focusNode: this._msgFN,
                              decoration: InputDecoration.collapsed(
                                hintText: 'Enter Message',
                                fillColor: Colors.white,
                              ),
                              keyboardType: TextInputType.text,
                              textInputAction: TextInputAction.send,
                              textCapitalization: TextCapitalization.sentences,
                              onSubmitted: (s) => this._sendMessage(
                                auth: auth,
                                main: main,
                                type: 'Text',
                                msg: s,
                              ),
                            ),
                          ),
                        ),
                      ),
                      GestureDetector(
                        child: Icon(Icons.send),
                        onTap: () => this._sendMessage(
                          auth: auth,
                          main: main,
                          type: 'Text',
                          msg: this._msgTEC.text,
                        ),
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ],
      );

  _scrollToBtm() {
    if (this._scrollController.hasClients)
      this._scrollController.animateTo(this._scrollController.position.maxScrollExtent,
          duration: const Duration(milliseconds: 500), curve: Curves.easeOut);
  }

  Future _sendMessage({AuthProvider auth, MainProvider main, String type, String msg}) async {
    if (msg.trim().isEmpty) return;

    var now = Services().values.now();

    Chat chat = Chat(
      chatID: this._chat == null ? APIs().chats.collection.doc().id : this._chat.chatID,
      users: [widget.user.userID, auth.user.userID],
      recentMessage: Message(
        owner: APIs().users.collection.doc(auth.user.userID),
        type: type,
        msg: msg,
        createdAt: now,
      ),
      createdAt: now,
      updatedAt: now,
    );
    await main
        .createChat(
      chat: chat,
      isCreating: this._chat == null,
    )
        .then((value) async {
      if (mounted)
        setState(() {
          if (this._chat == null) this._chat = chat;
          this._msgTEC.text = '';
        });

      this._scrollToBtm();

      Map<dynamic, dynamic> results = await Services().cloudFunction.notifyUserInChat(data: <String, dynamic>{
        'toUserID': widget.user.userID,
        'selfie': widget.user.profile.selfie,
        'name': widget.user.profile.name,
        'chatID': this._chat.chatID,
        'msg': msg,
        'tokens': widget.user.settings.tokens.fcm,
      });

      Funcs.log(results);
    });
  }

main_provider.dart-始终作为提供商窗口小部件收听

  MainProvider.instance() {
    this.readChats();
  }

  readChats() {
    var query = APIs()
        .chats
        .collection
        .where('users', arrayContainsAny: [Services().auth.currentUser().uid])
        .orderBy('updatedAt', descending: true)
        .limit(10);

    if (this.lastChat != null) query = query.startAfterDocument(this.lastChat);

    this._chatsStream = Services().crud.readLive(
          stream: query.snapshots(),
          onEmpty: () {
            Funcs.log('EMP');
            // chats.clear();
          },
          onAdded: (c) {
            Funcs.log('ADD');
            Chat chat = Chat.model(id: c.id, map: c.data());

            this.chats.add(chat);
            this.lastChat = c;

            notifyListeners();
          },
          onModified: (c) {
            Funcs.log('MOD');
            Chat chat = Chat.model(id: c.id, map: c.data());

            int index = this.chats.indexWhere((element) => element.chatID == chat.chatID);

            chat.messages = this.chats[index].messages;

            this.chats[index] = chat;
            this.chats.sort((a, b) => b.updatedAt.compareTo(a.updatedAt));

            notifyListeners();
          },
          onRemoved: (c) {
            Funcs.log('REM');
            Chat chat = Chat.model(id: c.id, map: c.data());
            int index = this.chats.indexWhere((element) => element.chatID == chat.chatID);

            this.chats.removeAt(index);

            notifyListeners();
          },
          onFailure: (e) => print(e),
        );
  }

0 个答案:

没有答案