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

如何使用whereArrayContains实现Firestore两个数组的元素逐个匹配

Firestore数组多元素包含匹配解决方案

问题原因

Firestore原生的whereArrayContains仅支持判断数组是否包含单个元素,whereArrayContainsAny仅支持判断数组是否包含给定列表中的任意一个元素,都不满足「包含给定列表全部元素」的查询需求,所以直接传入列表作为whereArrayContains的参数不会生效。

可行解决方案

方案1:服务端粗筛+客户端精筛(无需改数据结构,通用首选)

先从你要匹配的数组里挑1个出现频率低的元素,用whereArrayContains先过滤掉绝大多数不匹配的文档,拿到查询结果后在客户端做二次校验,判断文档的ingredients是否包含你自定义数组的所有元素。
修改后代码示例:

List<String> ingreList;
String[] ingredientLists;
String[] test = {"sugar","b"};

private void checkTesting() {
    // 先拿目标数组的第一个元素做粗筛,可替换为出现频率更低的元素提升效率
    postRef.whereArrayContains("ingredients", test[0])
            .get()
            .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
                @Override
                public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
                    postLists3.clear();
                    List<String> targetList = Arrays.asList(test);
                    for(QueryDocumentSnapshot documentSnapshot: queryDocumentSnapshots){
                        // 取出文档里的ingredients数组
                        List<String> docIngredients = (List<String>) documentSnapshot.get("ingredients");
                        // 二次校验:是否包含目标数组的所有元素
                        if (docIngredients != null && docIngredients.containsAll(targetList)) {
                            Post post = documentSnapshot.toObject(Post.class);
                            postLists3.add(post);
                        }
                    }
                    postAdapter.notifyDataSetChanged();
                    progressBar.setVisibility(View.GONE);
                }
            });
}
  • 优点:不需要修改现有数据结构,适配任意数量的匹配元素
  • 缺点:如果首次筛选命中的文档量很大,会有额外的带宽消耗

方案2:修改数据结构为Map类型(服务端直接过滤,性能最优)

提前修改Firestore的文档结构,新增ingredients_map字段,把每个食材作为key,value固定为true,示例结构:

{
  "ingredients": ["sugar", "b", "c"],
  "ingredients_map": {
    "sugar": true,
    "b": true,
    "c": true
  }
}

查询的时候链式调用whereEqualTo匹配所有你要的元素即可,修改后代码示例:

private void checkTesting() {
    Query query = postRef;
    // 循环添加所有匹配条件
    for (String ingredient : test) {
        query = query.whereEqualTo("ingredients_map." + ingredient, true);
    }
    query.get()
            .addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
                @Override
                public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
                    postLists3.clear();
                    for(QueryDocumentSnapshot documentSnapshot: queryDocumentSnapshots){
                        Post post = documentSnapshot.toObject(Post.class);
                        postLists3.add(post);
                    }
                    postAdapter.notifyDataSetChanged();
                    progressBar.setVisibility(View.GONE);
                }
            });
}
  • 优点:完全服务端过滤,查询效率最高
  • 限制:Firestore单条查询最多支持10个等值条件,如果你要匹配的元素超过10个不能使用该方案

特殊场景:完全匹配数组所有元素

如果你的需求是文档的ingredients和你自定义的数组完全相等(元素、顺序完全一致),直接用whereEqualTo传入List类型参数即可,原生支持:

postRef.whereEqualTo("ingredients", Arrays.asList(test))

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 10:24:05