Node.js初学者遇Cannot read property 'collection' of undefined错误求助
Hey there, Leon! Let’s break down that Cannot read property 'collection' of undefined error you’re hitting with your Node.js todo app—it’s almost always tied to how your MongoDB/Mongoose connection or data models are set up. Let’s walk through the most common issues and fixes, focusing on your key files:
app.js This is the #1 culprit for this error. If your app tries to access a database collection before the connection is fully established, Mongoose will return undefined for the collection reference.
Correct Connection Flow:
const express = require('express'); const mongoose = require('mongoose'); const app = express(); // 1. Connect to MongoDB FIRST, before loading models/routes mongoose.connect('mongodb://localhost:27017/todoDB', { useNewUrlParser: true, useUnifiedTopology: true }) .then(() => console.log('Successfully connected to MongoDB!')) .catch(err => console.error('MongoDB connection failed:', err)); // 2. THEN load your models and routes const Todo = require('./models/Todo'); // Make sure this path is correct! const todoRoutes = require('./routes/Todo'); // Middleware for parsing form data (critical for POST requests) app.use(express.urlencoded({ extended: true })); app.set('view engine', 'handlebars'); // Mount routes app.use('/', todoRoutes); app.listen(3000, () => console.log('Server running on port 3000'));
What to Avoid:
Never load your models or routes before establishing the MongoDB connection—this is the most common reason for the collection undefined error.
Chances are you’re missing a proper Mongoose model (or it’s incorrectly exported). Create a models/Todo.js file if you haven’t already, with this structure:
const mongoose = require('mongoose'); const todoSchema = new mongoose.Schema({ title: { type: String, required: true }, completed: { type: Boolean, default: false } }); // Export the model (this is how routes will access the collection) module.exports = mongoose.model('Todo', todoSchema);
If this file is missing, or the export is wrong, any attempt to access Todo.collection will throw your error.
routes/Todo.js Logic Make sure you’re correctly importing the model and using Mongoose’s built-in methods (instead of directly accessing collection, which is unnecessary here):
const express = require('express'); const router = express.Router(); const Todo = require('../models/Todo'); // Double-check this file path! // GET all todos router.get('/', async (req, res) => { try { const todos = await Todo.find(); // Use Mongoose's find() instead of collection res.render('index', { todos }); } catch (err) { res.status(500).send(`Error fetching todos: ${err.message}`); } }); // POST a new todo router.post('/', async (req, res) => { try { const newTodo = new Todo({ title: req.body.title // completed defaults to false, per our model }); await newTodo.save(); res.redirect('/'); // Redirect back to the todo list } catch (err) { res.status(500).send(`Error adding todo: ${err.message}`); } }); module.exports = router;
If the path to ../models/Todo is wrong (e.g., ./models/Todo if your routes folder is nested differently), Todo will be undefined, triggering the error.
views/index.handlebars Ensure your template is set up to receive and display the todos data correctly:
<h1>My Todo List</h1> <!-- Add Todo Form --> <form action="/" method="POST"> <input type="text" name="title" placeholder="Enter a new todo..." required> <button type="submit">Add Todo</button> </form> <!-- Todo List --> <ul> {{#each todos}} <li> {{title}} <span>({{completed ? 'Done' : 'Not Done'}})</span> </li> {{else}} <li>No todos yet! Add one above.</li> {{/each}} </ul>
This won’t fix the collection error directly, but it ensures your GET/POST requests render data correctly once the backend is fixed.
- Run your app and check the console: If you see a MongoDB connection error, fix that first (make sure MongoDB is running locally on port 27017, or update your connection string).
- Verify all file paths: A typo in
require('../models/Todo')is easy to miss and will break everything. - Avoid direct
collectionaccess: Mongoose’s methods likefind(),save(), etc., handle collection interactions safely—you rarely need to callcollectiondirectly.
内容的提问来源于stack exchange,提问作者Leon Bogod

