如何在Firestore中查询数组内Map匹配exercise_id的文档?
问题解答:基于Firestore数组嵌套字段过滤文档
一、现有结构下的可行方案
你要基于exercises数组内对象的exercise_id过滤文档,是可以实现的。Firestore支持通过点符号路径查询数组中的嵌套字段,会返回所有exercises数组中至少存在一个元素满足exercise_id匹配的文档。
示例代码(JavaScript):
// 假设你的集合名为workouts const db = firebase.firestore(); const workoutsQuery = db.collection('workouts') .where('exercises.exercise_id', '==', 'chin_up_assisted'); workoutsQuery.get() .then(snapshot => { snapshot.forEach(doc => { console.log('匹配的文档:', doc.id, doc.data()); }); }) .catch(err => { console.error('查询失败:', err); });
不过这种方案有几个局限:
- 查询返回的是整个文档,无法只提取数组中匹配的那个exercise对象;
- 如果
exercises数组非常大,查询性能会下降; - 无法直接对匹配的exercise对象做进一步的条件过滤(比如同时筛选
reps大于某个值的练习)。
二、更适合查询模式的数据结构优化
从NoSQL的设计原则出发,数据结构应该匹配你的查询需求。如果经常需要按exercise_id过滤,建议做以下优化:
方案1:新增单独的exercise_id数组
在文档中新增一个exercise_ids字段,仅存储所有练习的id字符串数组,原exercises数组保留完整信息:
{ "end_time": "2022-11-21T23:58:21.631441", "exercise_ids": ["chin_up_assisted", "triceps_dip_assisted"], "exercises": [/* 原数组内容 */], "owner": "vSq2Xp2y6GcnUA0yLBAtJcAnSbs1", ... }
这种结构下,你可以用array-contains做更高效的查询:
const workoutsQuery = db.collection('workouts') .where('exercise_ids', 'array-contains', 'chin_up_assisted');
如果需要同时查询多个exercise_id,可以用array-contains-any:
const workoutsQuery = db.collection('workouts') .where('exercise_ids', 'array-contains-any', ['chin_up_assisted', 'triceps_dip_assisted']);
方案2:将exercises拆分为子集合
如果需要更复杂的查询(比如按练习的reps、weight等字段过滤),可以把每个exercise作为workouts集合文档的子集合(比如子集合名为exercises),每个子文档对应一个练习:
workouts (集合) - workout_id1 (文档) - end_time: "2022-11-21T23:58:21.631441" - owner: "vSq2Xp2y6GcnUA0yLBAtJcAnSbs1" ... - exercises (子集合) - exercise_id1 (文档) - exercise_id: "chin_up_assisted" - exercise_name: "Chin Up (Assisted)" - sets: [/* 原sets数组 */] - exercise_id2 (文档) - exercise_id: "triceps_dip_assisted" ...
这种结构下,你可以直接查询子集合中匹配exercise_id的文档,或者用集合组查询跨所有workout查找特定练习:
// 查询某个workout下的特定练习 const exerciseQuery = db.collection('workouts').doc('workout_id1') .collection('exercises').where('exercise_id', '==', 'chin_up_assisted'); // 集合组查询:所有workout中包含特定练习的文档 const groupQuery = db.collectionGroup('exercises') .where('exercise_id', '==', 'chin_up_assisted');
内容的提问来源于stack exchange,提问作者rsharma
相关产品推荐
相关产品推荐

