Hazzaldo
Hazzaldo

Reputation: 563

Exporting Mongoose code in Node.js - pass value to callback from Mongoose method

I have two JS files: app.js which has the HTTP API method handlers, and model.js which contains the Mongoose (MongoDB) methods, which will be called/consumed by the app.js HTTP methods. Before, when I had all my code in one file (app.js) it was working perfectly. But when I split it to have Mongoose code separately then I had an error.

The website concept is, it displays a todo checklist, with the title of the list being "Today's" list. So in the database, there's a model List, which has a name field/property and an array of items (checklist items) field/property.

The idea is, when the website loads, the Home page displays Today's todo list. It does this by first checking in the Database, if there's a List object with the name Today's it renders it in the Home page, otherwise it creates this List object by calling methods in the model.js file, before rendering the Home page.

So the steps are:

1- In app.js, the app.get('/' ... method calls List.findOne Mongoose method in model.js, to check first if Today's List object exists in database.

2- If List.findOne finds Today's list object, I need to pass Today's list object to a callback, so that it can received in app.get('/'... method, which in turn will use it to render the Home page.

3- However, if List.findOne does not find Today's list object, then I need to pass something else back to the callback like a null, a string "null" or something to indicate that the List object Today's is not found. That way app.get('/'... method will receive something in the callback that indicate "list not found" and calls another Mongoose method to create Today's list object.

However, I'm just getting an error instead of being able to pass anything to the callback:

Error:

[nodemon] starting `node app.js`
Server started, listening on port: 3000
list not found
events.js:288
      throw er; // Unhandled 'error' event
      ^

ReferenceError: _ is not defined
    at Function.createNewListInDB (C:\Users\hazzaldo\Desktop\...\todolist-v2\model.js:72:29)
    at C:\Users\hazzaldo\Desktop\...\todolist-v2\app.js:22:23
    at C:\Users\hazzaldo\Desktop\...\todolist-v2\model.js:38:17
    at C:\Users\hazzaldo\Desktop\...\todolist-v2\node_modules\mongoose\lib\model.js:4849:16
    at C:\Users\hazzaldo\Desktop\...\todolist-v2\node_modules\mongoose\lib\model.js:4849:16
    at C:\Users\hazzaldo\Desktop\...\todolist-v2\node_modules\mongoose\lib\helpers\promiseOrCallback.js:24:16
    at C:\Users\hazzaldo\Desktop\...\todolist-v2\node_modules\mongoose\lib\model.js:4872:21
    at C:\Users\hazzaldo\Desktop\...\todolist-v2\node_modules\mongoose\lib\query.js:4379:11
    at C:\Users\hazzaldo\Desktop\...\todolist-v2\node_modules\kareem\index.js:135:16
    at processTicksAndRejections (internal/process/task_queues.js:79:11)
Emitted 'error' event on Function instance at:
    at C:\Users\hazzaldo\Desktop\...\todolist-v2\node_modules\mongoose\lib\model.js:4851:13
    at C:\Users\hazzaldo\Desktop\...\todolist-v2\node_modules\mongoose\lib\helpers\promiseOrCallback.js:24:16
    [... lines matching original stack trace ...]
    at processTicksAndRejections (internal/process/task_queues.js:79:11)
[nodemon] app crashed - waiting for file changes before starting...

Here's my code:

model.js:

const mongoose = require('mongoose');

//create DB
mongoose.connect('mongodb://localhost:27017/todolistDB', {useNewUrlParser: true, useUnifiedTopology: true, useFindAndModify: false });


//create schema
const itemsSchema = new mongoose.Schema ({
  name: String
});

const listSchema = new mongoose.Schema ({
  name: String,
  items: [itemsSchema]
});


//create model (aka Collection) (equivalent to Table in SQL))
const Item = mongoose.model('Item', itemsSchema);
const List = mongoose.model('List', listSchema);


class DBUtility {
    constructor() {
        console.log("Constructor class DBUtility");
    }

    // *** DB utility methods

    static findOneList(listName, callBack) {

        List.findOne({name: listName}, (err, foundList) => {
            if (err) {
                console.log(`Error: ${err}`);
            } else if (!foundList) {
                console.log('list not found');
                const value = 'null'
                callBack(value);   
            } else {
                console.log(`found list.`);
                callBack(foundList)
            }
        });
    }

    static createNewListInDB(listName) {
        //create default items for new list
        const introItem = new Item({
            name: 'Welcome to your todolist!'
        });

        const addItem = new Item({
            name: 'Hit the + button to add a new item.'
        });

        const deleteItem = new Item({
            name: '<-- Hit this to delete an item.'
        });

        const listNameCap = _.capitalize(listName);
        const list = new List({
            name: listNameCap,
            items: [introItem, addItem, deleteItem]
        });
        list.save(err => {
            if (err) return handleError(err);
            console.log(`List ${list} added successfully to DB.`);
        });
    }

}

exports.DBUtility = DBUtility;

app.js:

const express = require('express');
const bodyParser = require('body-parser');
const date = require(`${__dirname}\\date.js`);
const model = require(`${__dirname}\\model.js`);
const ejs = require('ejs');
const _ = require('lodash');

const app = express();

app.use(bodyParser.urlencoded({ extended: true }));
app.set('view engine', 'ejs');
app.use(express.static('public'));


//*** HTTP requests handlers

app.get('/', (req, res) => {
  const defaultListName = "Today's";
  const todayFormatted = date.getDate();
  model.DBUtility.findOneList(defaultListName, (foundList) => {
    if (foundList === 'null') {
      model.DBUtility.createNewListInDB(defaultListName);
      res.redirect('/');
    } else { 
      res.render('list', {
        listTitlePassToH1: foundList.name,
        todayDate: todayFormatted,
        listItems: foundList.items
      });
    }
  });
});

const port = 3000;
app.listen(port, () => {
  console.log(`Server started, listening on port: ${port}`);

I've looked at other similar posts on SO, and not sure if it's solving a similar issue to mine, but one post suggests using Promise on all Mongoose methods to ensure each operation is executed before moving to the next task. If this is the case for me, then I'm not quite sure how to apply it to my code.

Upvotes: 0

Views: 85

Answers (1)

ca1c
ca1c

Reputation: 1295

I am not sure if this is going to work but I have ran into this problem before. Try requiring lodash in your model.js file: const _ = require("lodash");.

Upvotes: 1

Related Questions