You need to enable JavaScript to run this app. Firestore数组存储场景下如何实现全局重名校验并拦截重复提交
优惠活动
大模型
产品
解决方案
定价
更多

Firestore数组存储场景下如何实现全局重名校验并拦截重复提交

现有逻辑的问题根源
  • 当前存储结构为「用户手机号作为文档ID,Name字段为数组结构存储用户输入的名称」,整个流程没有跨文档的全局校验环节:仅在当前用户对应的独立文档内做数组追加操作,完全不检查其他用户的文档中是否已经存在同名输入,因此不同用户提交同名时完全不会被拦截。
  • 用到的FieldValue.arrayUnion本身是幂等操作:如果数组中已经存在相同值,操作会直接静默成功,不会触发任何失败回调。因此同一用户重复提交已存在的名称时,代码会走到成功分支直接跳转页面,根本不会弹出错误提示。
改造实现方案

核心逻辑调整:用户提交时先执行全局查重,确认输入名称没有在任何用户的文档中出现过,再执行原有写入流程;如果查到重名,直接在输入框提示错误,终止后续写入操作。
这里采用Firestore自带的whereArrayContains查询条件,直接在整个Note集合中匹配Name数组包含目标名称的文档,不需要拉取全量文档遍历,查询效率更高。

改造后的完整代码:

private void storeNewUserData() {
    // 获取当前登录用户的手机号
    SharedPreferences preferences = getSharedPreferences(mypreferences, Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = preferences.edit();
    String currentUserPhone = preferences.getString("phoneNo", "");

    TextInputLayout ig_name = findViewById(R.id.ig_name);
    String inputName = Objects.requireNonNull(ig_name.getEditText()).getText().toString().trim();

    // 非空校验
    if (TextUtils.isEmpty(inputName)) {
        ig_name.setError("输入的名称不能为空");
        return;
    }

    // 全局查重:检索所有用户文档中是否已存在当前输入的名称
    firebaseFirestore
            .collection("Note")
            .whereArrayContains("Name", inputName)
            .get()
            .addOnCompleteListener(verifyTask -> {
                // 查询过程本身出错的处理
                if (!verifyTask.isSuccessful()) {
                    Toast.makeText(getApplicationContext(), "名称校验失败,请检查网络后重试", Toast.LENGTH_SHORT).show();
                    return;
                }

                // 查到重名,拦截操作
                if (!verifyTask.getResult().getDocuments().isEmpty()) {
                    ig_name.setError("该名称已被其他用户使用,请更换后提交");
                    return;
                }

                // 无重名,执行原有写入逻辑
                Map<String, Object> addUserToArrayMap = new HashMap<>();
                addUserToArrayMap.put("Name", FieldValue.arrayUnion(inputName));

                // 优先更新当前用户对应的已有文档
                firebaseFirestore
                        .collection("Note")
                        .document(currentUserPhone)
                        .update(addUserToArrayMap)
                        .addOnCompleteListener(updateTask -> {
                            if (updateTask.isSuccessful()) {
                                editor.apply();
                                Toast.makeText(getApplicationContext(), "successfully entered", Toast.LENGTH_SHORT).show();
                                Intent intent = new Intent(getApplicationContext(), secondActivity.class);
                                startActivity(intent);
                                finish();
                                return;
                            }

                            // 文档不存在时,执行新建操作
                            firebaseFirestore
                                    .collection("Note")
                                    .document(currentUserPhone)
                                    .set(addUserToArrayMap)
                                    .addOnSuccessListener(aVoid -> {
                                        editor.apply();
                                        Toast.makeText(getApplicationContext(), "successfully entered", Toast.LENGTH_SHORT).show();
                                        Intent intent = new Intent(getApplicationContext(), secondActivity.class);
                                        startActivity(intent);
                                        finish();
                                    })
                                    .addOnFailureListener(e2 -> 
                                        Log.w(TAG, "Error writing document", e2));
                        });
            });
}
注意事项
  • 上述方案可以覆盖绝大多数场景,但存在极端并发的竞态风险:如果两个用户在毫秒级的同一时间提交完全相同的名称,两人的查重请求都未查到旧数据,就会同时完成写入。如果需要100%保证名称全局唯一,建议单独搭建一个名称注册集合,将名称本身作为文档ID——依托Firestore文档ID的全局唯一性,写入重复ID时会直接触发失败回调,完全不需要额外查重。
  • 原代码中把editor.apply()放在了写入失败的分支里,存在持久化空值的逻辑漏洞,改造中已经将该操作移动到真正写入成功的分支执行。
  • 加上前置查重逻辑后,FieldValue.arrayUnion的静默幂等行为不会再造成“操作成功但无实际变更”的异常体验:所有重复名称都会在写入前被拦截,后续写入的都是全新的名称值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.02 02:24:08