React Native中Firestore多条件OR查询实现药物交互检测
你说得没错,Firestore确实不支持直接在单个查询里组合多个OR条件的复合查询——它的where子句默认都是AND关系。不过有两种简单可行的方案能解决你的需求,我来一步步给你讲:
方案一:发起两个并行查询,合并结果
既然不能用OR,那我们就分开查两种可能的配对情况,然后用Promise.all把两个查询的结果合并起来,最后判断有没有匹配的交互数据。
这里给你调整后的代码(注意我把异步操作的逻辑优化了,避免在render里直接执行的问题):
// 类组件里建议把这个逻辑放到componentDidUpdate或者componentDidMount里 componentDidUpdate(prevProps, prevState) { // 只有当atc1或atc2变化时才发起查询,避免重复请求 if (prevState.atc1 !== this.state.atc1 || prevState.atc2 !== this.state.atc2) { this.fetchInteraction(); } } fetchInteraction() { const { atc1, atc2 } = this.state; let interactionDescription = "No interaction"; // 同时发起两个查询:匹配(atc1, atc2)和(atc2, atc1) Promise.all([ dbh.collection('IX') .where('GRP1D', '==', atc1) .where('GRP2D', '==', atc2) .get(), dbh.collection('IX') .where('GRP1D', '==', atc2) .where('GRP2D', '==', atc1) .get() ]).then(([snapshot1, snapshot2]) => { // 优先检查第一个查询的结果 if (!snapshot1.empty) { interactionDescription = snapshot1.docs[0].data().MEASD; } // 第一个没结果,再看第二个 else if (!snapshot2.empty) { interactionDescription = snapshot2.docs[0].data().MEASD; } // 更新state来展示结果 this.setState({ interactionDescription }); console.log('Interaction:', interactionDescription); }).catch(error => { console.error('Failed to fetch interaction data:', error); }); } render() { const { interactionDescription } = this.state; return ( <View> {/* 展示交互结果 */} <Text>{interactionDescription}</Text> </View> ); }
这个方案的好处是不需要修改现有数据结构,直接就能用。缺点是需要发起两个查询,不过对于药物交互这种数据量不大的场景,性能影响可以忽略。
方案二:优化数据结构,用一次查询搞定
如果你希望更高效,建议在每个药物交互文档里添加一个排序后的组合字段,比如sortedATCs。比如当GRP1D是A01B、GRP2D是B02A时,把这两个ATC编号排序后拼成字符串(比如A01B_B02A)存到sortedATCs字段里。
这样查询的时候,你只需要把用户选择的两个ATC编号排序后,直接匹配这个字段就行:
fetchInteraction() { const { atc1, atc2 } = this.state; // 对两个ATC编号排序,生成查询用的键 const sortedATCKey = [atc1, atc2].sort().join('_'); dbh.collection('IX') .where('sortedATCs', '==', sortedATCKey) .get() .then(querySnapshot => { const interactionDescription = querySnapshot.empty ? "No interaction" : querySnapshot.docs[0].data().MEASD; this.setState({ interactionDescription }); console.log('Interaction:', interactionDescription); }).catch(error => { console.error('Error fetching interaction:', error); }); }
这个方案只需要一次查询,效率更高,而且代码更简洁。唯一的工作是需要批量更新现有文档,添加这个sortedATCs字段——如果数据量不大的话,用脚本跑一遍就行。
小提醒
不要在render方法里直接发起异步请求!因为每次组件render都会执行这段代码,会导致重复请求,甚至性能问题。把查询逻辑放到生命周期方法(比如componentDidUpdate、componentDidMount)或者函数组件的useEffect里,并且添加条件判断,只有当依赖的状态(比如atc1、atc2)变化时才执行。
内容的提问来源于stack exchange,提问作者landyandolt

