我的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',
},
],
};
我目前正在处理一堆承诺:
// 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个诺言才能实际显示数据;如果类别数量增加太多,执行时间可能会成为问题。
有什么比我要解决的更好的解决方案了吗?
答案 0 :(得分:1)
由于Firebase会为每个呼叫收费,因此我看不到这种扩展。
Firestore不根据“通话”收费。它收取读取的文档数量和传输的数据量。如果您需要阅读所有类别,则只需为阅读有关该馆藏的许多文件付费。读取您的文档多少次调用都没有关系(例外情况是返回0的查询仍然会读取一次)。
在实践中,等待1个返回N个文档的查询或N个分别返回1个文档的查询之间没有太大区别。您仍然只是在等待N种文档。使用Firestore,不会出现无法很好扩展的查询。限制因素总是将取决于收到的文档数,而不是查询数。您的代码将主要花费时间等待结果转移。当然,在内存中可以容纳的事物数量有一个实用的上限,但是Promise的数量并不会太大。
除此之外,我不明白您为什么在onSnapshot
中使用getItemsByCategory
。似乎您只想使用get()而不是在侦听器中仅接收一个结果。这样,您的代码就会简单得多。