从MongoDB获取数据后渲染模板的Express代码技术问询
Let's break down the issues in your code and fix them step by step—your core problem is handling asynchronous operations correctly in Express, which is super common when working with databases like MongoDB.
Key Issues in Your Original Code
Timing Mismatch with Async Operations
res.renderruns immediately after starting the MongoDB connection, before your database query finishes. That meansclientArrayis stillundefinedwhen you pass it to the template—your async code hasn't had time to populate it yet.Early Database Connection Closure
You're callingdb.close()right after starting the query, not waiting for the query to complete. This can kill the connection mid-query, leading to failed data fetching.Unnecessary JSON Stringification
Converting the document array to a string withJSON.stringifymakes it impossible to directly iterate over in your Handlebars template. Handlebars works with objects/arrays, not strings.Incomplete Error Handling
You're only logging errors to the console, but not sending any error response to the client—users will just get a hanging request or a generic error page.
Corrected Code (Using Async/Await for Readability)
Async/await makes asynchronous code much easier to follow and ensures your template only renders after the data is ready:
app.get('/clients', async (req, res) => { let dbConnection; try { // Establish connection to MongoDB dbConnection = await MongoClient.connect('mongodb://localhost:27017/Clients'); console.log('Connected to MongoDB server'); // Fetch all client documents as an array of objects const clientDocs = await dbConnection.collection('Clients').find().toArray(); // Render the template with the raw document array res.render('clients.hbs', { infoArray: clientDocs }); } catch (error) { console.error('Failed to fetch client data:', error); // Send an error response to the client res.status(500).render('error.hbs', { message: 'Could not load client information' }); } finally { // Ensure the database connection is closed, regardless of success/failure if (dbConnection) { dbConnection.close(); } } });
Alternative: Promise-Chain Syntax (If You Prefer)
If you don't want to use async/await, you can chain Promises to maintain correct execution order:
app.get('/clients', (req, res) => { MongoClient.connect('mongodb://localhost:27017/Clients') .then(db => { console.log('Connected to MongoDB server'); // Chain the query, and ensure connection closes when done return db.collection('Clients').find().toArray() .finally(() => db.close()); }) .then(clientDocs => { res.render('clients.hbs', { infoArray: clientDocs }); }) .catch(error => { console.error('Error fetching data:', error); res.status(500).render('error.hbs', { message: 'Failed to load client data' }); }); });
Example Handlebars Template (clients.hbs)
Now that you're passing a raw array of objects, you can iterate over it directly in your template:
<h1>Client Directory</h1> {{#if infoArray}} <div class="client-list"> {{#each infoArray}} <div class="client-card"> <h3>{{name}}</h3> <p>Email: {{email}}</p> <p>Phone: {{phone}}</p> <!-- Add other fields from your MongoDB documents here --> </div> {{/each}} </div> {{else}} <p>No clients found in the database.</p> {{/if}}
Quick Notes
- Make sure your MongoDB service is running locally on port 27017, and the
Clientsdatabase/collection exists. - For production, consider using a connection pool instead of opening/closing connections per request—it's more efficient.
内容的提问来源于stack exchange,提问作者Harshit Gupta

