当有数千个文档时,如何优化 Firebase Firestore 请求?

问题描述 投票:0回答:1

我在 NextJS 中开发了一个网页,它获取存储在 Firestore 数据库中的调查并将数据呈现为不同的图表,该页面由一些客户使用,每月生成一些调查,但有一个客户端生成数千个调查,并且由于这个原因以及当前用于从数据库获取数据的方法,增加了页面的加载时间,下面您可以看到执行此操作的函数:

export const getBusinessDataFromUser = async (userId: string) => {
    const userDocRef = doc(getFirebase().db, USERS_COLLECTION_NAME, userId || '');

    try {
        const [userDocSnap, businessDocSnap] = await Promise.all([
            getDoc(userDocRef),
            getBusinessDocSnap(userId)
        ]);

        const userData: User = userDocSnap.data() as User;
        const businessData: Business = businessDocSnap.data() as Business;

        const response = {
            ...businessData,
            parentId: userData.businessId,
            Id: userData.businessId,
            customers: [] as Customer[],
            feedbacks: [] as (Feedback | FeedbackHooters)[],
            sucursales: [] as Branch[],
            meseros: [] as Waiter[]
        };

        response.Icono = await getBusinessIcon(businessData);
        await Promise.all([
            fetchCustomersAndFeedbacks(response, businessDocSnap.ref, businessData),
            fetchBranches(response, businessDocSnap.ref, userData.businessId, businessData),
            fetchMainWaiters(response, businessDocSnap.ref, businessData)
        ]);

        return response;
    } catch (error) {
        console.error('Error al obtener información del negocio:', error);
        return null;
    }
};

async function fetchCustomersAndFeedbacks(response: any, businessDocRef: DocumentReference, businessData: Business) {
    const customersQuery = collection(businessDocRef, 'customers');
    const customersSnapshot = await getDocs(customersQuery);

    await Promise.all(customersSnapshot.docs.map(async (customerDoc) => {
        const customerData = customerDoc.data() as Customer;
        const customerFeedbacksQuery = collection(customerDoc.ref, 'feedbacks');
        const customerFeedbacksSnapshot = await getDocs(customerFeedbacksQuery);
        let feedbacks: (Feedback | FeedbackHooters)[] = [];

        customerFeedbacksSnapshot.docs.forEach((feedbackDoc) => {
            const feedbackData = feedbackDoc.data();
            if (businessData.parentId === 'hooters') {
                feedbacks.push({...feedbackData as FeedbackHooters, Visits: feedbacks.length});
            } else {
                feedbacks.push({...feedbackData as Feedback, Visits: feedbacks.length});
            }
        });
        response.customers.push({
            ...customerData,
            feedbacks: feedbacks
        });
    }));
}

async function fetchBranches(response: any, businessDocRef: DocumentReference, parentId: string, businessData: Business) {
    const branchesSnapshot = await getDocs(collection(businessDocRef, 'sucursales'));
    const branchesData = await Promise.all(branchesSnapshot.docs.map(async (branchDoc) => {
        const branchData = branchDoc.data() as Branch;
        const branch = {
            ...branchData,
            parentId: parentId,
            customers: [] as Customer[],
            feedbacks: [] as (Feedback | FeedbackHooters)[],
            meseros: [] as Waiter[]
        };
        await Promise.all([
            fetchCustomersAndFeedbacks(branch, branchDoc.ref, businessData),
            fetchWaiters(branch, branchDoc.ref, businessData)
        ]);
        return branch;
    }));
    response.sucursales = branchesData;
}

async function fetchWaiters(branch: any, branchDocRef: DocumentReference, businessData: Business) {
    const waitersSnapshot = await getDocs(collection(branchDocRef, 'meseros'));
    await Promise.all(waitersSnapshot.docs.map(async (waiterDoc) => {
        const waiterData = waiterDoc.data() as Waiter;
        const waiter = {
            ...waiterData,
            customers: [] as Customer[],
            feedbacks: [] as (Feedback | FeedbackHooters)[]
        };
        await fetchCustomersAndFeedbacks(waiter, waiterDoc.ref, businessData);
        branch.meseros.push(waiter);
    }));
}

async function fetchMainWaiters(response: any, businessDocRef: DocumentReference, businessData: Business) {
    const waitersSnapshot = await getDocs(collection(businessDocRef, 'meseros'));
    const waitersData = await Promise.all(waitersSnapshot.docs.map(async (waiterMainDoc) => {
        const waiterData = waiterMainDoc.data() as Waiter;
        const waiter = {
            ...waiterData,
            customers: [] as Customer[],
            feedbacks: [] as Feedback[]
        };
        await fetchCustomersAndFeedbacks(waiter, waiterMainDoc.ref, businessData);

        return waiter;
    }));

    response.meseros = waitersData;
}

async function getBusinessDocSnap(userId: string) {
    const userDocRef = doc(getFirebase().db, USERS_COLLECTION_NAME, userId || '');
    const userDocSnap = await getDoc(userDocRef);
    const userData: User = userDocSnap.data() as User;
    const businessDocRef = doc(getFirebase().db, DASHBOARD_COLLECTION_NAME, userData.businessId || '');
    return getDoc(businessDocRef);
}

功能

fetchCustomersAndFeedbacks
是从每个分店的每个顾客的反馈收集和客户的服务员收集中获取调查的功能,需要很多时间才能完成的线路是
const customerFeedbacksSnapshot = await getDocs(customerFeedbacksQuery);
。这种方法使函数抛出错误
Too many outstanding requests

因此,我需要一些帮助来优化从 Firebase 检索这些数据的方式,考虑到该客户自使用我的产品之日起已有数千份调查,而且我不得不说,现在我想获取所有数据然后使用它按日期过滤并与数据交互,无需加载时间,只需页面首次加载时的加载时间,因此请随时建议您认为更好的不同方法。

提前谢谢您。

firebase google-cloud-firestore next.js
1个回答
0
投票

从服务器加载所有文档,然后在客户端将其过滤到用户感兴趣的文档,这是一种浪费。即使你设法让它变得更快,你的限制在哪里? 10,000 个文档? 10万?它只是无法扩展,也无法执行。

每当您为单个用户请求加载数千个文档时,您的数据模型就会出现问题。您的应用程序应该只加载用户实际交互的数据,并且用户不会查看所有这些文档中的所有数据。

所以:

  1. 使用限制仅从服务器获取前N个文档,并且
  2. 如果您希望允许用户滚动到下一个 N 个文档,请使用分页。
  3. 使用查询仅从服务器检索用户感兴趣的文档。
© www.soinside.com 2019 - 2024. All rights reserved.