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

Firebase获取指定子节点Keys到ArrayList出错,仅返回Ingridients,求解决

Firebase Database无法获取目标节点Keys的问题排查与解决

需求背景

我需要先将IngridientIdOne下的所有keys存入ArrayList,再将IngridientIdTwo下的所有keys存入ArrayList。

数据库结构

{ "Receptes" : { "Ingridients" : { "IngridientIdOne" : { "Carrot" : true, "Salt" : true, "Apples" : true }, "IngridientIdTwo" : { "Strawberries" : true, "Sugar" : true, "Bananas" : true } } } }

尝试的代码

DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference(); 
DatabaseReference ingridientsRef = rootRef.child("Receptes").child("Ingridients"); 
ValueEventListener valueEventListener = new ValueEventListener() { 
    @Override 
    public void onDataChange(DataSnapshot dataSnapshot) { 
        for(DataSnapshot ds : dataSnapshot.getChildren()) { 
            String ingridient = ds.getKey(); 
            Log.d("TAG", ingridient); 
        } 
    } 
    @Override 
    public void onCancelled(DatabaseError databaseError) {} 
}; 
ingridientsRef.addListenerForSingleValueEvent(valueEventListener);

遇到的问题

日志中仅输出Ingridients,没有获取到IngridientIdOne、IngridientIdTwo下的目标keys,请问错误原因是什么?该如何实现需求?


错误原因分析

先帮你拆解问题:

  1. 你说日志只输出Ingridients,这和你贴的代码逻辑不符——按照代码写法,遍历dataSnapshot.getChildren()应该拿到IngridientIdOne和IngridientIdTwo的key才对。大概率是测试时的代码与贴出的不一致(比如误写了Log.d("TAG", dataSnapshot.getKey())),或者数据库权限/路径拼写存在问题。
  2. 核心逻辑问题:就算你拿到了IngridientIdOne和IngridientIdTwo的key,当前代码也没有深入到它们的子节点去获取食材keys——遍历只停留在ID节点这一层,没有继续往下遍历食材节点。

正确实现方案

下面给你两种靠谱的实现方式,按需选择:

方案一:一次性读取所有节点,分批次存入ArrayList

适合需要同时处理两个节点数据的场景:

DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference ingridientsRef = rootRef.child("Receptes").child("Ingridients");

// 初始化存储食材的列表
ArrayList<String> idOneIngredients = new ArrayList<>();
ArrayList<String> idTwoIngredients = new ArrayList<>();

ValueEventListener valueEventListener = new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        // 第一层遍历:拿到IngridientIdOne和IngridientIdTwo节点
        for (DataSnapshot idSnapshot : dataSnapshot.getChildren()) {
            String currentId = idSnapshot.getKey();
            
            // 判断当前是哪个ID节点,分别处理
            if ("IngridientIdOne".equals(currentId)) {
                // 第二层遍历:获取该ID下的所有食材key
                for (DataSnapshot ingredientSnap : idSnapshot.getChildren()) {
                    String ingredient = ingredientSnap.getKey();
                    idOneIngredients.add(ingredient);
                    Log.d("TAG", "IngridientIdOne 食材:" + ingredient);
                }
            } else if ("IngridientIdTwo".equals(currentId)) {
                for (DataSnapshot ingredientSnap : idSnapshot.getChildren()) {
                    String ingredient = ingredientSnap.getKey();
                    idTwoIngredients.add(ingredient);
                    Log.d("TAG", "IngridientIdTwo 食材:" + ingredient);
                }
            }
        }
        
        // 数据处理完成,这里可以使用两个列表
        Log.d("TAG", "IngridientIdOne 列表:" + idOneIngredients.toString());
        Log.d("TAG", "IngridientIdTwo 列表:" + idTwoIngredients.toString());
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        // 一定要处理错误,方便排查问题
        Log.e("TAG", "数据库读取失败:" + databaseError.getMessage());
    }
};
ingridientsRef.addListenerForSingleValueEvent(valueEventListener);

方案二:分别监听指定节点(更高效)

如果只需要这两个特定节点的数据,直接监听单个节点会更高效,避免读取多余数据:

DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
ArrayList<String> idOneIngredients = new ArrayList<>();
ArrayList<String> idTwoIngredients = new ArrayList<>();

// 监听IngridientIdOne节点
DatabaseReference idOneRef = rootRef.child("Receptes").child("Ingridients").child("IngridientIdOne");
idOneRef.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for (DataSnapshot ds : dataSnapshot.getChildren()) {
            idOneIngredients.add(ds.getKey());
        }
        Log.d("TAG", "IngridientIdOne 食材列表:" + idOneIngredients.toString());
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        Log.e("TAG", "读取IngridientIdOne失败:" + databaseError.getMessage());
    }
});

// 监听IngridientIdTwo节点
DatabaseReference idTwoRef = rootRef.child("Receptes").child("Ingridients").child("IngridientIdTwo");
idTwoRef.addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for (DataSnapshot ds : dataSnapshot.getChildren()) {
            idTwoIngredients.add(ds.getKey());
        }
        Log.d("TAG", "IngridientIdTwo 食材列表:" + idTwoIngredients.toString());
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        Log.e("TAG", "读取IngridientIdTwo失败:" + databaseError.getMessage());
    }
});

额外注意事项

  • 权限检查:确保你的Firebase数据库规则允许读取Receptes/Ingridients节点,否则会导致onDataChange无法获取数据。
  • 拼写一致性:节点名称的大小写、拼写必须和数据库里完全一致(比如Ingridients和ingridients是两个不同的节点)。
  • 错误处理:永远不要忽略onCancelled方法,这里能帮你快速定位权限不足、网络异常等问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:07:19