You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firebase/React中UpdateDoc更新userChats集合为空问题求助

问题:React+Firebase实时聊天中userChats集合始终为空

我用React开发实时私密聊天功能,搜索用户后,预期会更新Firebase的userChats集合,但该集合一直是空的。已经修改过Firestore规则,问题还是没解决。

相关代码

import React, { useContext, useState } from "react";
import {
  collection,
  query,
  where,
  getDocs,
  setDoc,
  doc,
  updateDoc,
  serverTimestamp,
  getDoc,
} from "firebase/firestore";
import { db } from "./firebase.js";
import { AuthContext } from "../context/AuthContext";
const Search = () => {
  const [username, setUsername] = useState("");
  const [user, setUser] = useState(null);
  const [err, setErr] = useState(false);

  const { currentUser } = useContext(AuthContext);

  const handleSearch = async () => {
    const q = query(
      collection(db, "users"),
      where("displayName", "==", username)
    );

    try {
      const querySnapshot = await getDocs(q);
      querySnapshot.forEach((doc) => {
        setUser(doc.data());
      });
    } catch (err) {
      setErr(true);
    }
  };

  const handleKey = (e) => {
    e.code === "Enter" && handleSearch();
  };

  const handleSelect = async () => {
    //check whether the group(chats in firestore) exists, if not create
    const combinedId = 
      currentUser.uid > user.uid
        ? currentUser.uid + user.uid
        : user.uid + currentUser.uid;
    try {
      const res = await getDoc(doc(db, "chats", combinedId));

      if (!res.exists()) {
        //create a chat in chats collection
        await setDoc(doc(db, "chats", combinedId), { messages: [] });

        //create user chats
        await updateDoc(doc(db, "userChats", currentUser.uid), {
          [combinedId + ".userInfo"]: {
            uid: user.uid,
            displayName: user.displayName,
          },
          [combinedId + ".date"]: serverTimestamp(),
        });
        console.log(user.displayName);
        await updateDoc(doc(db, "userChats", user.uid), {
          [combinedId + ".userInfo"]: {
            uid: currentUser.uid,
            displayName: currentUser.displayName,
          },
          [combinedId + ".date"]: serverTimestamp(),
        });
      }
    } catch (err) {}

    setUser(null);
    setUsername("")
  };
  return (
    <div className="search">
      <div className="searchForm">
        <input
          type="text"
          placeholder="Find a user"
          onKeyDown={handleKey}
          onChange={(e) => setUsername(e.target.value)}
          value={username}
        />
      </div>
      {err && <span>User not found!</span>}
      {user && (
        <div className="userChat" onClick={handleSelect}>
          <img src={user.photoURL} alt="" />
          <div className="userChatInfo">
            <span>{user.displayName}</span>
          </div>
        </div>
      )}
    </div>
  );
};

export default Search;

当前Firestore规则

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read,write: if true;
    }
  }
}

预期的userChats集合结构

userChats Collection:
  Document 1 (currentUser.uid):
    - Chat1 (ID): 
      - userInfo:
        - uid: (ID of the other user)
        - displayName: (Name of the other user)
      - date: (Date of the last message)
    - Chat2 (ID):
      - userInfo:
        - uid: (ID of the other user)
        - displayName: (Name of the other user)
      - date: (Date of the last message)

  Document 2 (another user.uid):
    - Chat1 (ID): 
      - userInfo:
        - uid: (ID of the currentUser)
        - displayName: (Name of the currentUser)
      - date: (Date of the last message)
    - Chat3 (ID):
      - userInfo:
        - uid: (ID of the other user)
        - displayName: (Name of the other user)
      - date: (Date of the last message)

问题排查与修复方案

1. 核心问题:updateDoc无法创建新文档

updateDoc仅能修改已存在的文档,如果userChats下对应用户UID的文档不存在,调用updateDoc不会自动创建它,这是集合为空的主要原因。需要先检查文档是否存在,不存在时用setDoc初始化。

2. 其他优化点

  • 搜索时限制结果数量,避免多个匹配用户导致的状态覆盖
  • 给错误捕获块添加日志输出,方便排查问题
  • 增加用户对象的有效性校验,避免undefined错误

修改后的关键代码

优化handleSearch函数

const handleSearch = async () => {
  const q = query(
    collection(db, "users"),
    where("displayName", "==", username),
    limit(1) // 只取第一个匹配结果
  );

  try {
    const querySnapshot = await getDocs(q);
    if (querySnapshot.empty) {
      setErr(true);
      setUser(null);
      return;
    }
    querySnapshot.forEach((doc) => {
      setUser(doc.data());
    });
    setErr(false);
  } catch (err) {
    setErr(true);
    console.error("搜索用户失败:", err);
  }
};

修复handleSelect函数

const handleSelect = async () => {
  if (!currentUser || !user) return;
  
  const combinedId = currentUser.uid > user.uid
    ? currentUser.uid + user.uid
    : user.uid + currentUser.uid;
  
  try {
    const chatDocRef = doc(db, "chats", combinedId);
    const chatDocSnap = await getDoc(chatDocRef);

    if (!chatDocSnap.exists()) {
      await setDoc(chatDocRef, { messages: [] });
      
      // 处理当前用户的userChats文档
      const currentUserChatRef = doc(db, "userChats", currentUser.uid);
      const currentUserChatSnap = await getDoc(currentUserChatRef);
      
      const chatData = {
        [combinedId]: {
          userInfo: {
            uid: user.uid,
            displayName: user.displayName,
          },
          date: serverTimestamp(),
        }
      };
      
      if (currentUserChatSnap.exists()) {
        await updateDoc(currentUserChatRef, chatData);
      } else {
        await setDoc(currentUserChatRef, chatData);
      }
      
      // 处理对方用户的userChats文档
      const otherUserChatRef = doc(db, "userChats", user.uid);
      const otherUserChatSnap = await getDoc(otherUserChatRef);
      
      const otherChatData = {
        [combinedId]: {
          userInfo: {
            uid: currentUser.uid,
            displayName: currentUser.displayName,
          },
          date: serverTimestamp(),
        }
      };
      
      if (otherUserChatSnap.exists()) {
        await updateDoc(otherUserChatRef, otherChatData);
      } else {
        await setDoc(otherUserChatRef, otherChatData);
      }
    }
  } catch (err) {
    console.error("创建/更新聊天失败:", err);
    setErr(true);
  }

  setUser(null);
  setUsername("");
};

内容的提问来源于stack exchange,提问作者Roberto Tavarez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 15:59:54