В моей базе данных 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 обещаний покажет данные; Время выполнения может быть проблемой, если количество категорий слишком велико.
Есть ли лучшее решение, чем я нашел?