Firebase查询返回动态键名对象,如何提取内部数据?
提取Firebase Realtime Database查询结果中动态键下的数据
你遇到的问题很常见——当使用orderByChild + equalTo查询时,哪怕只匹配到一条数据,Firebase返回的快照依然会包裹在一个动态生成的节点键里,而不是直接返回目标对象。所以你直接访问question.id时,实际上是在访问外层对象的id属性,自然拿不到正确的值。
这里有两种可靠的解决方式,推荐第一种(更鲁棒):
方法1:使用snapshot.forEach()遍历子节点
Firebase的快照对象提供了forEach()方法,用来遍历所有匹配的子节点。哪怕只有一个匹配项,这个方法也会执行一次,帮你拿到真正的目标数据:
componentDidMount() { const questionsRef = firebase.database().ref('Works') .orderByChild('firebaseKey') .equalTo(this.props.match.params.id); questionsRef.on('value', (snapshot) => { // 初始化默认状态,防止无匹配数据时出错 let newState = { id: '', category: '', level: '', pointAmount: 0, pointBoost: 0, photoURL: '' }; // 遍历匹配到的子节点(这里只会有一个) snapshot.forEach((childSnapshot) => { const questionData = childSnapshot.val(); newState = { id: questionData.id, category: questionData.category, level: questionData.level, pointAmount: questionData.pointAmount, pointBoost: questionData.pointBoost, photoURL: questionData.photoURL, }; }); console.log(newState); this.setState({ question: newState }); }); }
方法2:直接提取对象的第一个值(适合确定唯一匹配的场景)
如果你能保证firebaseKey是唯一的,不会有多个匹配结果,也可以用Object.values()把外层对象转成数组,直接取第一个元素:
componentDidMount() { const questionsRef = firebase.database().ref('Works') .orderByChild('firebaseKey') .equalTo(this.props.match.params.id); questionsRef.on('value', (snapshot) => { const questionObj = snapshot.val(); // 先判断是否有匹配数据 if (!questionObj) { console.log('未找到匹配的数据'); return; } // 取第一个值 const questionData = Object.values(questionObj)[0]; const newState = { id: questionData.id, category: questionData.category, level: questionData.level, pointAmount: questionData.pointAmount, pointBoost: questionData.pointBoost, photoURL: questionData.photoURL, }; console.log(newState); this.setState({ question: newState }); }); }
为什么推荐方法1?
方法1更安全:如果查询没有匹配到任何数据,forEach不会执行,你可以保留初始化的默认状态;而方法2如果没有匹配数据,Object.values(undefined)[0]会直接报错,需要额外的判断逻辑。
内容的提问来源于stack exchange,提问作者Alex Ironside
相关产品推荐
相关产品推荐

