我的 Firestore 数据库中有两个集合,相当于:
// ItemCategories collection
{
id_category_1: {
name: 'Category 1',
},
id_category_2: {
name: 'Category 2',
},
id_category_3: {
name: 'Category 3',
},
// ...
}
// Items collection
{
id_item_1: {
CategoryId: 'id_category_1',
name: 'Item 1',
},
id_item_2: {
CategoryId: 'id_category_1',
name: 'Item 2',
},
id_item_3: {
CategoryId: 'id_category_3',
name: 'Item 3',
},
id_item_4: {
CategoryId: 'id_category_2',
name: 'Item 4',
},
// ...
}
我想检索并格式化我的项目以按类别分隔,如下所示:
const ItemList = {
'Category 1': [
{
id: 'id_item_1',
CategoryId: 'id_category_1',
name: 'Item 1',
},
{
id: 'id_item_2',
CategoryId: 'id_category_1',
name: 'Item 2',
},
],
'Category 2': [
{
id: 'id_item_4',
CategoryId: 'id_category_2',
name: 'Item 4',
},
],
'Category 3': [
{
id: 'id_item_3',
CategoryId: 'id_category_3',
name: 'Item 3',
},
],
};
我目前正在处理一堆 Promise:
// Function to retrieve Items for a given CategoryId
const getItemsByCategory = async CategoryId => {
const Items = await new Promise(resolve => {
firebase
.firestore()
.collection('items')
.where('CategoryId', '==', CategoryId)
.orderBy('name', 'ASC')
.onSnapshot(querySnapshot => {
const values = [];
querySnapshot.forEach(doc => {
values.push({
...doc.data(),
key: doc.id,
});
});
resolve(values);
});
});
return Items;
};
// Function to actually get all the items, formatted as wanted
export const getItemList = () => {
return dispatch => { // I'm in a Redux Action
const Items = {};
firebase
.firestore()
.collection('itemCategories')
.orderBy('name', 'ASC')
.get() // Categories can't be changed
.then(querySnapshot => {
const Promises = [];
querySnapshot.forEach(doc => {
const category = doc.data().name;
const P = new Promise(resolve => {
getItemsByCategory(doc.id).then(values => {
const result = {
category,
values,
};
resolve(result);
});
});
Promises.push(P);
});
Promise.all(Promises).then(values => {
values.forEach(v => {
Items[v.category] = v.values;
});
// Here I have the formatted items
console.log(Items);
//dispatch(setItemList(Items)); // Redux stuff
});
});
}
};
这段代码可以工作,但我觉得应该有办法优化它。我至少可以看到两个问题:
此代码进行(N+1) Firestore 调用(其中 N 是类别数)。由于 Firebase 对每次调用收费,因此我看不到这种扩展。
我们必须等待 N 个 promise 才能实际显示数据;如果类别数量增长太多,执行时间可能会成为问题。
还有比我得到的更好的解决方案吗?
最佳答案
As Firebase charges every call, I can't see this scaling.
Firestore 不会根据“通话”收费。它按读取的文档数量和传输的数据量收费。如果您需要阅读所有类别,那么您只需支付阅读该馆藏的一些文档的费用。无论您花费多少次调用来读取这些文档(异常(exception)情况是返回 0 个结果的查询仍会产生一次读取)。
实际上,等待 1 个返回 N 个文档的查询与等待 N 个返回 1 个文档的查询之间并没有太大区别。不管怎样,你仍然只是在等待 N 个文档。借助 Firestore,所有查询都可以很好地扩展。限制因素始终取决于收到的文档数量,而不是查询数量。您的代码将主要花费时间等待结果传输。当然,内存中可以保存的内容数量有一个实际上限,但 Promise 的数量不会有什么大不了的。
除此之外,我不明白您为什么在 getItemsByCategory
中使用 onSnapshot
。似乎您只想使用 get() 而不是在监听器中仅接收一个结果。这样你的代码就会简单得多。
关于javascript - 优化在 Firebase Firestore 中检索按另一个集合分组的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55622691/