Langkah 1: Kursor MongoDB
Begini cara kami menyediakan kursor (menggunakan semula coretan anda):
const cursor = userObject?.data?.serviceProviderName === 'ZYRO' ? zyroTransactionModel.find(query).cursor() : finoTransactionModel.find(query).cursor(); console.log("Cursor created successfully");
Langkah 2: Sediakan Fail ZIP
Gunakan pustaka yazl untuk menstrim data CSV ke dalam fail ZIP:
const yazl = require('yazl'); const zipfile = new yazl.ZipFile(); reply.raw.writeHead(200, { "Content-Type": "application/zip", "Content-Disposition": "attachment; filename=transactions.zip", }); zipfile.outputStream.pipe(reply.raw); const cleanup = async () => { console.log("Cleaning up resources..."); zipfile.end(); // Finalize ZIP await cursor.close(); }; reply.raw.on("close", cleanup); reply.raw.on("error", cleanup);
Langkah 3: Mencipta Strim CSV Dinamik
Jana data CSV secara dinamik dan strimkannya ke dalam fail ZIP:
const createNewCSVStream = (headers) => { const csvStream = new Readable({ read() {} }); csvStream.push(headers.join(",") + "\n"); // Add headers return csvStream; }; const filteredHeaders = getHeaders(transactionDownloadFields, userObject?.state?.auth?.role); const currentCSVStream = createNewCSVStream(filteredHeaders); zipfile.addReadStream(currentCSVStream, "transactions_part_1.csv");
Langkah 4: Menstrim Data MongoDB ke CSV
Strim data daripada MongoDB terus ke CSV:
cursor.on('data', (doc) => { const csvRow = filteredHeaders.map(header => doc[header.key] || '').join(','); currentCSVStream.push(csvRow + '\n'); // Write row }); cursor.on('end', () => { currentCSVStream.push(null); // End the stream zipfile.end(); // Finalize the ZIP });
Langkah 5: Memproses Data daripada Kursor MongoDB
Strim dokumen daripada kursor MongoDB, ubahnya mengikut keperluan dan tulis baris secara dinamik ke strim CSV:
try { for await (const doc of cursor) { if (clientDisconnected) { console.log("Client disconnected. Stopping processing..."); break; } streamedCount++; rowCount++; let row = ""; const filteredHeaders = getHeaders( transactionDownloadFields, userObject?.state?.auth?.role ); for (let i = 0; i < filteredHeaders.length; i++) { const field = filteredHeaders[i]; // Fetch the corresponding field configuration from transactionDownloadFields const originalField = transactionDownloadFields.find((f) => f.value === field.value); // Get the value from the transaction document let value = getValueFromTransaction(doc, field.value); // Apply transformation if the field has a transform function if (originalField?.transform) { value = originalField.transform(value); } // Enclose the value in double quotes value = value !== undefined ? `"${value}"` : '"N/A"'; row += (i > 0 ? "," : "") + value; } row += "\n"; currentCSVStream.push(row); // Check if the row count has reached the threshold for the current CSV file if (rowCount >= MAX_ROWS_PER_FILE) { console.log(`Threshold reached for file ${fileIndex - 1}. Starting new file...`); currentCSVStream.push(null); // End the current CSV stream currentCSVStream = createNewCSVStream(); // Start a new stream rowCount = 0; // Reset the row count } } // Finalize the current CSV stream if it has data if (currentCSVStream) { currentCSVStream.push(null); } // Finalize the ZIP file zipfile.end(); console.log(`Successfully streamed ${streamedCount} rows across ${fileIndex - 1} files.`); } catch (error) { console.error("Error during processing:", error); if (!headersSent) reply.status(500).send({ error: "Failed to generate ZIP file" }); } finally { // Cleanup: Close the MongoDB cursor await cursor.close().catch((err) => console.error("Error closing cursor:", err)); }
Ringkasan
Penggunaan Lelaran Dokumen untuk menunggu...daripada:
Strim dokumen satu demi satu daripada kursor MongoDB dengan cekap.
Mendayakan pemprosesan masa nyata tanpa memuatkan semua data ke dalam memori.
Membina setiap baris secara dinamik dengan mengulangi pada Headers yang ditapis.
Menggunakan transformasi menggunakan fungsi transformasi, jika ditakrifkan dalam transactionDownloadFields.
Ambang Baris dan Pemisahan Fail:
Memantau kiraan baris terhadap ambang (MAX_ROWS_PER_FILE).
Menamatkan strim CSV semasa dan memulakan strim baharu apabila ambang dicapai.
Melog dan menghantar respons ralat jika isu berlaku semasa pemprosesan.
Memastikan pembersihan yang betul dengan menutup kursor MongoDB dalam blok akhirnya.
Menolak null untuk menamatkan strim CSV semasa.
Melengkapkan fail ZIP setelah semua baris diproses.
Atas ialah kandungan terperinci Dari Storan ke Strim: Menghantar Data MongoDB Terus kepada Pengguna. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!