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

Time:04-30

Error: throw er; // Unhandled 'error' event

TypeError: Cannot read properties of null (reading 'items') at 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:[email protected]/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  id="heading">
        <h1> <%= listTitle %> </h1>
      </div>
    
      <div >
        <% newListItems.forEach((listItem) => { %>
          <form action="/delete" method="post">
            <div >
              <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  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") -%>

CodePudding user response:

The problem seems to be at your schema, you are not making it the right way, instead of passing an object to moongose.model like this:

const itemsSchema = { 
  name: String
};

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

You should create a schema with the class Schema from mongoose, so try the following:

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

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

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

And in your listSchema do the following:

// 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()

Further up, in your 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"})
  }
});

See 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 from mongoose as well, almost everything you need is at the docs. Hope I helped you!

  • Related