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

Firestore如何查询不存在指定token_id的文档并避免重复创建

问题根因

你当前代码出现重复数据的核心原因有3个:

  • 查询逻辑完全写反:使用whereField("token_id", isNotEqualTo: user_token)会返回所有token_id不等于当前值的文档,只要集合里存在任意一条其他token的记录,查询结果就非空,但你没有判断查询结果里是否包含当前token,反而直接执行写入逻辑,必然会重复创建文档。
  • 先查后写存在竞态风险:就算把查询条件改成isEqualTo匹配当前token,遇到客户端重复触发、网络重试等场景时,可能出现多个请求同时查到「无对应文档」,进而先后写入多条重复数据。
  • 写入时未绑定唯一约束:调用db.collection("tokenList").document()会生成随机ID的新文档,没有和user_token做绑定,天然无法从数据库层面阻止重复数据生成。

你遇到的重复数据问题示例:
两个文档存在相同token_id,出现重复数据

最优实现方案

不要用先查再写的逻辑,直接利用Firestore文档ID的全局唯一特性实现去重,可靠性最高、性能最好:

  • 将user_token直接作为tokenList集合下的文档ID,同一个token永远只会对应唯一文档,从数据库底层避免重复条目生成,不需要提前做存在性查询。
  • 重复触发写入时只会更新同一条文档的内容,不会产生新的重复文档,完全满足业务需求。

对应实现代码:

// 初始化配置
let db = Firestore.firestore()
let user_token = "dpc3GPfPzUArj...IdEac5hWYWI8"

// 直接用user_token作为文档ID,天然唯一
let tokenDocRef = db.collection("tokenList").document(user_token)
// 写入数据,同token多次调用只会操作同一条文档
tokenDocRef.setData([
    "token_id": user_token,
    "subscribeTime": Timestamp()
]) { err in
    if let err = err {
        print("token记录写入失败: \(err.localizedDescription)")
    } else {
        print("token记录已生效,无重复数据")
    }
}

严格不覆盖已有数据的实现

如果业务要求「文档已存在时完全不做任何写入修改」,可以用事务保证原子性,避免竞态:

let tokenDocRef = db.collection("tokenList").document(user_token)
db.runTransaction({ (transaction, errorPointer) -> Any? in
    let snapshot: DocumentSnapshot
    do {
        try snapshot = transaction.getDocument(tokenDocRef)
    } catch let err as NSError {
        errorPointer?.pointee = err
        return nil
    }
    // 仅当文档不存在时执行创建
    if !snapshot.exists {
        transaction.setData([
            "token_id": user_token,
            "subscribeTime": Timestamp()
        ], forDocument: tokenDocRef)
    }
    return nil
}) { _, err in
    if let err = err {
        print("事务执行失败: \(err.localizedDescription)")
    } else {
        print("操作完成,无重复数据")
    }
}

注意:如果一定要用token_id字段做匹配而不是用文档ID,必须配合Firestore安全规则做唯一校验兜底,否则仅靠客户端的查询+写入逻辑永远无法100%避免并发导致的重复数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 10:30:39