Node.js如何实现返回Sequelize查询结果数组的Promise函数?
Hey there! The core issue with your current getInvoicesCount function is that you're returning the promiseInvoices array synchronously, but Sequelize's findAll is an asynchronous operation—so the array is still empty when you return it. Let's adjust this to make the function return a Promise, so you can properly fetch the populated data with .then() in your main code.
Option 1: Modify with Promise Chains
We'll have the function return the entire findAll Promise chain, and return your final data array at the end of the chain:
function getInvoicesCount() { let userInvCount = 0; let deletedUserInvCount = 0; let userInvAmount = 0; let deletedUserInvAmount = 0; let monthWiseInvCount = []; // Return the Promise chain directly return db.userInvoices .findAll({ attributes: [ 'deleted_at', [sequelize.fn('COUNT', sequelize.col('id')), 'count'], [sequelize.fn('SUM', sequelize.col('invoice_amount')), 'amount'], [sequelize.fn('MONTH', sequelize.col('invoice_date')), 'month'] ], group: ['invoice_date', 'deleted_at'], paranoid: false }) .then(result => { result.forEach(element => { const data = element.dataValues; userInvCount += data.count; userInvAmount += data.amount; if (data.deleted_at !== null) { deletedUserInvAmount += data.amount; deletedUserInvCount += data.count; } // Clean up the deleted_at field (fixed your original flawed map logic) const { deleted_at, ...monthData } = data; monthWiseInvCount.push(monthData); }); // Return the final array to pass to .then() return [ userInvCount, userInvAmount, deletedUserInvCount, deletedUserInvAmount, monthWiseInvCount ]; }) .catch(error => { // Don't forget to handle errors! console.error('Failed to fetch invoice data:', error); throw error; // Re-throw to let the caller handle it too }); }
Option 2: Use Async/Await (Recommended)
Async functions automatically return a Promise, and this syntax is much cleaner for asynchronous logic:
async function getInvoicesCount() { let userInvCount = 0; let deletedUserInvCount = 0; let userInvAmount = 0; let deletedUserInvAmount = 0; let monthWiseInvCount = []; try { // Wait for the Sequelize query to complete const result = await db.userInvoices.findAll({ attributes: [ 'deleted_at', [sequelize.fn('COUNT', sequelize.col('id')), 'count'], [sequelize.fn('SUM', sequelize.col('invoice_amount')), 'amount'], [sequelize.fn('MONTH', sequelize.col('invoice_date')), 'month'] ], group: ['invoice_date', 'deleted_at'], paranoid: false }); result.forEach(element => { const data = element.dataValues; userInvCount += data.count; userInvAmount += data.amount; if (data.deleted_at !== null) { deletedUserInvAmount += data.amount; deletedUserInvCount += data.count; } const { deleted_at, ...monthData } = data; monthWiseInvCount.push(monthData); }); // Return the array—async function wraps it in a Promise return [ userInvCount, userInvAmount, deletedUserInvCount, deletedUserInvAmount, monthWiseInvCount ]; } catch (error) { console.error('Failed to fetch invoice data:', error); throw error; } }
How to Call the Function and Access the Array
Now in your main code, you can use .then() to get the populated array, and even destructure it for easier access:
getInvoicesCount() .then(invoicesData => { // Destructure the array into individual variables const [ userInvCount, userInvAmount, deletedUserInvCount, deletedUserInvAmount, monthWiseInvCount ] = invoicesData; // Use your data here console.log('Total invoices:', userInvCount); console.log('Total invoice amount:', userInvAmount); console.log('Deleted user invoices count:', deletedUserInvCount); console.log('Deleted user invoices amount:', deletedUserInvAmount); console.log('Month-wise invoice data:', monthWiseInvCount); }) .catch(error => { // Handle any errors propagated from the function console.error('Error processing invoice data:', error); });
Quick Notes on Improvements
- I fixed the logic to remove the
deleted_atfield frommonthWiseInvCount—your originalmapapproach wasn't working correctly, so destructuring is a more reliable solution. - Added error handling with
.catch()(for Promise chains) andtry/catch(for async/await) to avoid unhandled Promise rejections. - Async/await is generally easier to read and maintain, especially if you add more asynchronous steps later.
内容的提问来源于stack exchange,提问作者daksh bhardwaj

