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

如何在React项目中基于regNo避免Cloud Firestore重复条目?

问题:React + Cloud Firestore 如何用regNo作为主键避免重复条目并提示用户

我编写了一段向Cloud Firestore提交数据的React代码,表单中设置了唯一标识字段regNo,希望将regNo作为主键避免重复条目,当该regNo已存在时向应用用户弹出提示。我尝试通过在提交逻辑中增加regNo是否为null的判断来实现,但未达到预期效果。

原有提交逻辑代码

import Sidebar from './../../components/sidebar/Sidebar';
import Navbar from './../../components/navbar/Navbar';
import "./new.scss"
import { useEffect, useState } from 'react';
import DriveFolderUploadIcon from '@mui/icons-material/DriveFolderUpload';
import { addDoc, collection,doc,getDoc,serverTimestamp, setDoc} from "firebase/firestore";
import { db } from '../../firebase';
import { useNavigate, useParams } from 'react-router-dom';
import { isEmpty } from 'lodash';
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

const New = ({ title, btnUpd }) => {
  const [file, setFile] = useState("");
  const navigate = useNavigate();

  const findUs = ["Referral Doctor", "Website", "Friends", "Facebook", "Nil"]

  const statusCheck = ["married", "divorced", "single"]

  const titled = ["Mr", "Mrs"]

  const sexes = ["Male", "Female"]

  const [userInfo, setUserInfo] = useState({
    regNo: "",
    title: "",
    firstName: "",
    lastName: "",
    sex: "",
    email: "",
    reffBy: "",
    address: "",
    phoneNumber: "",
    age: "",
    date: "",
    birth: "",
    status: "",
    state: "",
    occupation: "",
    duration: "",
    finding: "",
  });

  const {userId}  = useParams();
  let id = userId
  
  useEffect(() => {
    let getUserDoc = async (id) => {
      let docRef = doc(db, "mrisystems/" + id);
      let docSnap = await getDoc(docRef);
      console.log('getUserDoc() received:', docSnap);
      if (docSnap.exists) {
        let theData = docSnap.data();
        console.log('getUserDoc() setting userInfo:', theData);
        setUserInfo(theData);
      }
    }
  
    if (id) {
      getUserDoc(id);
      console.log("IdUser", id)
    } else {
      console.log('useEffect() -- no ID value');
    }
  }, [id]);

  const handleInput = (e) => {
    const {name, value} = e.target;
    setUserInfo({...userInfo, [name]: value});
  }

  // 新增/更新现有记录逻辑
  const handleAdd = async(e) => {
      e.preventDefault();
        if(isEmpty(id)){
        await addDoc(collection(db, "mrisystems"), {
          ...userInfo,
          timeStamp: serverTimestamp(),
        });    
        toast.error("用户已存在");
      } else {
        await setDoc(doc(db, "mrisystems/" + id), {
          ...userInfo,
          timeStamp: serverTimestamp(),
        });    
      }
      navigate("/users")
  }
}

我尝试修改后的提交逻辑代码

// 新增/更新现有记录逻辑
const handleAdd = async(e) => {
  e.preventDefault();
    if(isEmpty(id) && userInfo.regNo===null){
    await addDoc(collection(db, "mrisystems "), {
      ...userInfo,
      timeStamp: serverTimestamp(),
    });    
    toast.error("用户已存在");
  } else {
    await setDoc(doc(db, "mrisystems/" + id), {
      ...userInfo,
      timeStamp: serverTimestamp(),
    });    
  }
  navigate("/users")
}

解决方案

你的核心问题在于没有真正去Firestore查询regNo是否已存在,且本地判断逻辑错误(初始regNo是空字符串而非null)。要实现用regNo作为主键并避免重复,需要以下步骤:

  1. 放弃addDoc(自动生成随机ID),改用setDoc指定regNo作为文档ID,利用Firestore同一集合下文档ID唯一的特性保证主键唯一性。
  2. 提交前先查询Firestore中是否存在ID为regNo的文档,存在则提示用户,不存在再创建。

修改后的handleAdd函数:

// 新增/更新记录逻辑
const handleAdd = async(e) => {
  e.preventDefault();
  
  // 先校验regNo是否为空
  if (!userInfo.regNo.trim()) {
    toast.error("请填写注册编号");
    return;
  }

  if (isEmpty(id)) {
    // 新增模式:检查regNo是否已存在
    const docRef = doc(db, "mrisystems", userInfo.regNo);
    const docSnap = await getDoc(docRef);
    
    if (docSnap.exists()) {
      toast.error("该注册编号已存在");
      return;
    }
    
    // 不存在则创建,用regNo作为文档ID
    await setDoc(docRef, {
      ...userInfo,
      timeStamp: serverTimestamp(),
    });
    toast.success("用户创建成功");
  } else {
    // 更新模式:直接更新对应ID的文档
    await setDoc(doc(db, "mrisystems", id), {
      ...userInfo,
      timeStamp: serverTimestamp(),
    });
    toast.success("用户更新成功");
  }
  
  navigate("/users");
}

额外说明

  • 用regNo作为文档ID后,后续查询、更新该用户时,直接通过regNo定位文档即可,无需依赖自动生成的ID。
  • 可以给Firestore的regNo字段添加唯一索引(虽然用文档ID已经天然唯一,但添加索引能增强数据校验)。
  • 建议在表单层面增加regNo的格式校验,避免非法字符作为文档ID。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 16:05:13