TypeError: Cannot read properties of null (reading 'items')

TypeError: Cannot read properties of null (reading 'items')

错误:抛出错误; // 未处理的 'error' 事件

TypeError: 无法读取 null 的属性(读取 'items') 在 C:\Users\shiva\Desktop\Web Development\todolist\app.js:105:17

getting the error in the 1st app.post method -> else statement. stuck at it for almost a day. ps: code might not run as db link is changed by me


    const express = require("express");
    const bodyParser = require("body-parser");
    const mongoose = require("mongoose");
    const _ = require("lodash");
    
    const app = express();
    
    app.set('view engine', 'ejs');
    
    app.use(bodyParser.urlencoded({extended: true}));
    app.use(express.static("public"));
mongoose.connect("mongodb+srv://adminshivam:refd3sfde@cluster0.3igye.mongodb.net/todolistDB");


    
    const itemsSchema = { 
      name: String
    };
    
    const Item = mongoose.model("Item", itemsSchema);
    
    
    const item1 = new Item({
      name: "Welcome to your todolist!"
    });
    
    const item2 = new Item({
      name: "Hit the + button to add a new item."
    });
    
    const item3 = new Item({
      name: "<-- Hit this to delete an item."
    });
    
    const defaultItems = [item1, item2, item3];
    
    const listSchema = {
      name: String,
      items: [itemsSchema]
    };
    
    const List = mongoose.model("List", listSchema);
    
    
    app.get("/", function(req, res) {
    
      Item.find({}, function(err, foundItems){
    
        if (foundItems.length === 0) {
          Item.insertMany(defaultItems, function(err){
            if (err) {
              console.log(err);
            } else {
              console.log("Successfully savevd default items to DB.");
            }
          });
          res.redirect("/");
        } else {
          res.render("list", {listTitle: "Today", newListItems: foundItems});
        }
      });
    
    });
    
    app.get("/:customListName", function(req, res){
      const customListName = _.capitalize(req.params.customListName);
    
      List.findOne({name: customListName}, function(err, foundList){
        if (!err){
          if (!foundList){
            //Create a new list
            const list = new List({
              name: customListName,
              items: defaultItems
            });
            list.save();
            res.redirect("/" + customListName);
          } else {
            //Show an existing list
    
            res.render("list", {listTitle: foundList.name, newListItems: foundList.items});
          }
        }
      });
    
    
    
    });
    
    app.post("/", function(req, res){
    
      const itemName = req.body.newItem;
      const listName = req.body.list;
    
      const item = new Item({
        name: itemName
      });
    
      if (listName === "Today"){
        item.save();
        res.redirect("/");
      } else {
        List.findOne({name: listName}, function(err, foundList){
          foundList.items.push(item);
          foundList.save();
          res.redirect("/" + listName);
        });
      }
    });
    
    app.post("/delete", function(req, res){
      const checkedItemId = req.body.checkbox;
      const listName = req.body.listName;
    
      if (listName === "Today") {
        Item.findByIdAndRemove(checkedItemId, function(err){
          if (!err) {
            console.log("Successfully deleted checked item.");
            res.redirect("/");
          }
        });
      } else {
        List.findOneAndUpdate({name: listName}, {$pull: {items: {_id: checkedItemId}}}, function(err, foundList){
          if (!err){
            res.redirect("/" + listName);
          }
        });
      }
    
    
    });
    
    app.get("/about", function(req, res){
      res.render("about");
    });
    
    app.listen(3000, function() {
      console.log("Server started on port 3000");
    });

error link from above code foundList.items.push(item);

list.ejs


    <%- include("header") -%>
    
      <div class="box" id="heading">
        <h1> <%= listTitle %> </h1>
      </div>
    
      <div class="box">
        <% newListItems.forEach((listItem) => { %>
          <form action="/delete" method="post">
            <div class="item">
              <input type="checkbox" name="checkbox" value="<%= listItem._id %>" onChange="this.form.submit()">
              <p><%=  listItem.name  %></p>
            </div>
            <input type="hidden" name="listName" value="<%= listTitle %>"></input>
          </form>
          <% });%>
    
          <form class="item" action="/" method="post">
            <input type="text" name="newItem" placeholder="New Item" autocomplete="off">
            <button type="submit" name="list" value="<%= listTitle %> ">+</button>
          </form>
      </div>
    
    <%- include("footer") -%>

问题似乎出在您的架构上,您没有按照正确的方式进行操作,而不是像这样将对象传递给 moongose.model

const itemsSchema = { 
  name: String
};

const Item = mongoose.model("Item", itemsSchema);

您应该使用来自 mongoose 的 class Schema 创建一个模式,因此请尝试以下操作:

const mongoose = require("mongoose");
const { Schema } = mongoose

const itemsSchema = new Schema({
  name: {type: String, required: true}
})

const Item = mongoose.model("Item", itemsSchema)

然后在您的 listSchema 中执行以下操作:

// removed const defaultItems = [item1, item2, item3];

const listSchema = new Schema({
  name: {type: String, required: true},
  // define an array of id that references the Item schema
  items: [{type: ObjectId, ref: "Item", required: true, default: [] }]
});

const List = mongoose.model("List", listSchema);

// the object named as list1 will contain a reference to id of  item1, item2 and item3.

const list1 = new List({name: "list1", items: [item1._id, item2._id, item3._id]}).save()

更进一步,在您的 post api 中:

app.post("/", async function(req, res){

  const itemName = req.body.newItem;
  const listName = req.body.list;
  try {
    const item = new Item({ name: itemName });

    if (listName === "Today") {
      await item.save();
      res.redirect("/");
    } else {
      // save the item id to items field from list schema
      const list = await List.findOne({ name: listName })
      list.items.push(item._id)
      await list.save()

      // don't make a redirect within the database query
      res.redirect("/" + listName);
    }
  } catch(err) {
    // If some error was threw handle it here
    // you can handle mongoose errors as follow:
    if(err instanceof mongoose.Error) {
      // use a custom message or err.message
      res.status(500).json({message: "error with Db"})
    }
    res.status(500).json({message: "something went wrong"})
  }
});

也可以从 mongoose 查看 the docs to know more about it, as you are using references between your schemas I suggest you to take a look at the populate method because probably you will need it in the future. See the available queries,几乎所有你需要的都在文档中。希望对你有所帮助!