Node.JS, Express & MongoDB Atlas:: Multiple Collections ejs - node.js

I have tried almost all the solutions but couldn't get this fixed.
I'm trying to get multiple collection of data (Mongodb Atlas) onto one ejs file. But I can't get data onto the rendered ejs sheet. But when I tested with locus I can see all the data received from the database up to res.render("/vendor/show"). But it is not passing onto ejs template.
I have three sets of data sitting on the mongo Atlas:
const vendorSchema = new mongoose.Schema({
name:String,
image:String,
imageId:String,
});
const newpromoSchema = new mongoose.Schema({
name:String,
image:String,
imageId:String,
vendor:String,
description:String,
sdate:String,
edate:String,
});
const neweventSchema = new mongoose.Schema({
name:String,
image:String,
imageId:String,
description:String,
vendor:String,
sdate:String,
edate:String,
});
router.get("/vendors/:id",function(req,res) {
var events={}; //Create Empty event Object
var promotions={}; //Create Empty promotion Object
var vendors={};//Create Empty vendor Objext
Promotion.find({},function (err,allPromotions) {
if (err) {
console.log(err);
} else {
//Find Collection And Assign It To Object
promotions=allPromotions;
}
});
Event.find({},function(err, allEvents) {
if (err) {
console.log(err);
} else {
events=allEvents;
}
});
Vendor.find({},function(err,allVendors){
if(err){
console.log(err);
}else{
vendors=allVendors;
//find order collection and passing it to ejs templates
res.render("vendors/show",{ event:events, promotion:promotions vendor:vendors});
}
});
});
Show.ejs code as
<%=vendor.name%>
<%=promotion.name%>
<%=event.name%>

You need to handle the async process. In your current code, there are three async processes. Please go through following the link you will definitely get an idea about it.
https://blog.risingstack.com/mastering-async-await-in-nodejs/
if you need more help Don’t hesitate to comment.

I managed to get all data using the below function. But now I have another issue, need to filter all the Promotions and Events by vendor But it doesn't filter.
Data Schema
const neweventSchema = new mongoose.Schema({
name:String,
image:String,
imageId:String,
description:String,
vendor:String,
sdate:String,
edate:String,
});
const Event = mongoose.model("Event",neweventSchema);
module.exports = Event;
//SCHEMA SETUP===============================================================================================================
const newpromoSchema = new mongoose.Schema({
name:String,
image:String,
imageId:String,
vendor:String,
description:String,
sdate:String,
edate:String,
});
//compile into a model
const Promotion = mongoose.model('Promotion',newpromoSchema);
module.exports = Promotion;
//SCHEMA SETUP===============================================================================================================
const vendorSchema = new mongoose.Schema({
name:String,
image:String,
imageId:String,
});
const Vendor = mongoose.model("Vendor", vendorSchema);
module.exports = Vendor;
Routes as below
router.get("/vendors/:id", function (req, res) {
Vendor.find({}, function (err, allVendors) {
if (err) {
console.log(err);
} else {
// //Find Collection And Assign It To Object
Event.find({}, function (err, allEvents) {
if (err) {
console.log(err);
} else {
Promotion.find({}, function (err, allPromotions) {
if (err) {
console.log(err);
} else {
//find order collection and passing it to ejs templates
res.render("vendors/show", {event: allEvents, promo: allPromotions, vendor: allVendors});
}
});
}
});
}
});
});
EJS Show page But It doesn't get filtered.
<!-- Trying to filter all the events by vendor if event's vendor name == vendor name then show on the show page -->
<%if(event.vendor === vendor.name){%>
<div class = "container-fluid">
<div class = "row">
<%event.forEach(function(events){%>
<div class="col-sm-6 col col-md-4 col-lg-3">
<div class="thumbnail">
<img src ="</%=events.image%>" class="rounded" width="304" height="236">
<div class="caption">
<h4><%=events.name%></h4>
<p class="font-italic font-weight-bold text-muted">
<%=events.vendor%>
</p>
<p><strong>Start Date</strong><%=events.sdate%></p>
<p><strong>End Date</strong><%=events.edate%></p>
</div>
<p>Event Details <br>
<%=events.description.substring(0,100)%>
</p>
<p>
Find More
</p>
</div>
</div>
<%})%>
</div>
</div>
<%}%>
<!-- //Trying to filter all the promotions by vendor if vendor name= to promotions's vendor name only show in the show page-->
<%if(promo.vendor===vendor.name){%>
<div class = "container-fluid">
<div class = "row">
<%promo.forEach(function(promotions){%>
<div class="col-sm-6 col col-md-4 col-lg-3">
<div class="thumbnail">
<img src ="<%=promotions.image%>" class="rounded" width="304" height="236">
<div class="caption">
<h4><%=promotions.name%></h4>
<p class="font-italic font-weight-bold text-muted"> <%=promotions.vendor%></p>
<p><strong>Start Date</strong> <%=promotions.sdate%></p>
<p><strong>End Date</strong> <%=promotions.edate%></p>
</div>
<p>
<%=promotions.description.substring(0,100)%>
</p>
<p>
Find More
</p>
</div>
</div>
<%})%>
</div>
</div>
<%}%>

Related

Mongoose schema not showing in view

I created a schema for the supports tickets I have to show on this view but, they are not actually showing. The data is showing in the console so I don't really understand the problem.
const mongosee = require ('mongoose');
const {Schema} = mongosee;
const AssignedTicketSchema = new Schema ({
name: { type: String, required: true},
pnumber: { type: String, required: true},
problem: { type: String, required: true},
support: {type: String, required: true},
date: { type: Date, default: Date.now}
});
module.exports = mongosee.model('AssignedTicket', AssignedTicketSchema)
These are the routes
router.post('/tickets/assign-tickets', isAuthenticated, async (req, res) => {
const {name, pnumber, problem, support}= req.body;
const newAssignedTicket = new AssignedTicket({name, pnumber, problem, support})
newAssignedTicket.user = req.user.id;
await newAssignedTicket.save();
req.flash('success_msg', 'Ticket assigned succesfully')
res.redirect('/tickets/assigned-tickets');
});
router.get('/assigned-tickets', isAuthenticated, async (req, res) => {
const assignedtickets = await AssignedTicket.find({user: req.user.id}).lean().sort({date: 'desc'});
res.render('tickets/assigned-tickets', {assignedtickets} );
});
And this is the view
<div class="row">
{{#each assignedtickets}}
<div class="col-md-3">
<div class="card">
<div class="card-body">
<h4 class="card-name d-flex justify-content-between align-items-center">
{{name}}
</h4>
<p>{{pnumber}}</p>
<p>{{problem}}</p>
<p>{{support}}</p>
</div>
</div>
</div>
{{else}}
<div class="card mx-auto">
<div class="card-body">
<p class="lead">There are no support tickets yet.</p>
Create a new support ticket
</div>
</div>
{{/each}}
</div>
From this line
res.redirect('/tickets/assigned-tickets');
Are you expecting to redirect to this method?
router.get('/assigned-tickets', isAuthenticated, async (req, res) => {
const assignedtickets = await AssignedTicket.find({user: req.user.id}).lean().sort({date: 'desc'});
res.render('tickets/assigned-tickets', {assignedtickets} );
});
Seems like the path is not an exact match.
Also, the redirect seems like is not sending the user id, probably you can send it as a parameter?
Check this other answers How do I redirect in expressjs while passing some context?
Express.js: Is it possible to pass an object to a redirect like it is with res.render?
how to pass data and redirect in express

Trouble rendering of documents with referenced fields on Vue.js mongoose

Recently, I picked up Vue.js and Mongoose to develop a personal project to mainly track Ingredients' on hand quantities on a certain online game.
Different dishes require different ingredients. Lotus Seed - Bird Egg soup, Jewelry Soup and Jade Parcels all require different number of Lotus Head as its ingredients.
I update an ingredient's quantity by using updateOne on ingredients collection.
Unfortunately, I originally embedded the ingredients on foods / dishes, which I realized problematic
recently, coz literally you just count ingredients what you currently have.
So a food document now looks like this
{
"_id" : ObjectId("5fca4ada32195d5814510242"),
"foodName" : "Lotus Seed and Bird Egg Soup",
"onHandQty" : 20,
"ingredients" : [
"5fca481432195d581451023f",
"5fca483932195d5814510240",
"5fca48a232195d5814510241"
]
}
I read about Mongoose's populate(), and tested to output one food/dish. Unfortunately there's nothing coming out of Vue.js front-end after trying that code.
server/models/Food.js
const { Router } = require('express');
const FoodItem = require('../../models/Food');
const IngredientItem = require('../../models/Ingredient');
const router = Router()
router.get('/', async(req, res) =>{
try {
const food = await FoodItem.findOne({
foodName: 'Lotus Seed and Bird Egg Soup'
}).populate('ingredients').
exec(function (err, food) {
if (err) return handleError(err);
console.log('The food is %s', food.foodName);
});
res.send(food);
} catch (error) {
res.status(500).json({
message: error.message
})
}
});
module.exports = router
A portion of component where ingredients are rendered
client/src/components/Food.vue
<div class="tile is-ancestor">
<div class="tile">
<div class="tile is-parent">
<div class="tile is-child box">
<template v-if="food.ingredients">
<div class="ingredients-block">
<p>Ingredients List:</p>
<ul class="ingredients-list">
<li class="row" v-for="ingredient in food.ingredients" :key="ingredient._id">
<div id="ingredient-image-container">
<img class="image is-64x64" :src="require(`../assets/images/food_inv/${ingredient.imagePath}.png`)" alt="ingredient.ingredientName" :title="ingredient._id">
{{ingredient.ingredientName}}
</div>
<div class="required-qty-container">
<!-- <i class="material-icons" id="required-inner-qty">food_bank</i> -->
Required:
{{ ingredient.requiredQty }}
</div>
<div class="on-hand-qty-container">
<p>On Hand:</p>
<input v-if="ingredient.onHandQty < ingredient.requiredQty" class="input is-danger on-hand-input" type="number" v-model="ingredient.onHandQty" min="0">
<input v-else class="input is-primary on-hand-input" type="number" v-model="ingredient.onHandQty" min="0">
<!-- <button class="button is-primary save-button" #click="test({ingredient_id: ingredient._id, onhandqty: ingredient.onHandQty})"><i class="material-icons">save</i></button> -->
<button class="button is-primary save-button" #click="$emit('update-qtys', {ingredient_id: ingredient._id, onhandqty: ingredient.onHandQty})"><i class="material-icons">save</i></button>
</div>
</li>
</ul>
</div>
</template>
</div>
</div>
</div>
</div>
Whole project on Github: Food Inventory
Quick Fixes,
change your food schema's ingredients field from object to array,
const foodSchema = new mongoose.Schema(
{
foodName: String,
imagePath: String,
effect: String,
onHandQty: Number,
// correct this to array
ingredients: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Ingredient'
}]
}
);
there are 2 ways to call mongoose methods first exec() with callback and second without exec() callback,
exec with callback that you have used buy need to send response (res.send(food) or res.json(food)) from inside the exec call function,
router.get('/', async(req, res) =>{
try {
await FoodItem.find()
.populate('ingredients')
.exec(function (err, food) {
if (err) return handleError(err);
console.log('The food is %s', food);
// put response here
res.json(food);
});
} catch (error) {
res.status(500).json({ message: error.message })
}
});
exec without call back
router.get('/', async(req, res) =>{
try {
const food = await FoodItem.find()
.populate('ingredients')
.exec();
res.json(food);
} catch (error) {
res.status(500).json({ message: error.message })
}
});

Not able to post data to database and database is not showing in Robo 3T (MongoDB/Mongoose/Express)

I'm a beginner web developer (currently in the learning phase).
So, I was trying to make my first minor backend project (a todo app) and ran into a problem with the database.
I'm using MongoDB and Mongoose as database setup and express with NodeJS as backend (with ejs as template engine).
The problem is I'm not able to post stuff to the database. It is giving error when I'm submitting the form (POST method).
And the after setting up a connection, It is not showing on Robo 3T.
I'm not sure where I'm going wrong. Please help me out with this.
The used files are attached below.
Directory structure
index.js
/** #format */
//requiring express
const express = require("express");
//setting up the port
const port = 1111;
//this module provides a way to work with directories and file paths
const path = require("path");
//requiring configuration for setting up the database to be accessed by mongoose
const db = require("./config/mongoose");
//requiring Task schema/model
//using this we will create entries and populate our collection
const Task = require("./models/task");
const { create } = require("./models/task");
//firing up express
const app = express();
app.set("view engine", "ejs");
app.set("views", path.join(__dirname, "views"));
app.use(express.urlencoded({ extended: true }));
app.use(express.static(__dirname + "/assets"));
let task_list = [
{
title: "College",
due_date: "2012-12-13",
category: "College"
},
{
title: "Home",
due_date: "2012-12-13",
category: "Home"
},
{
title: "Work",
due_date: "2012-12-13",
category: "Work"
},
{
title: "Group",
due_date: "2012-12-13",
category: "Group"
},
];
app.get("/", function (req, res) {
Task.find({}, function (err, task) {
if (err) {
console.log("Error occured!");
return;
}
return res.render("home", {
tasks: task
});
});
});
app.post("/new-task", function (req, res) {
console.log(req.body);
Task.create(
{
title: req.body.title,
due_date: req.body.due_date,
category: req.body.category
},
function (err, newt) {
if (err) {
console.log("Error while posting");
return;
}
console.log("Newtask created!: ", newt);
return res.redirect("back");
}
);
});
//creating a listener to the specified port
app.listen(port, function (err) {
if (err) {
console.log(`Some error occured at port: ${port}
Please try again later`);
return;
}
console.log("Yay! Server is running at # port:", port);
});
Note: I was using task_list array to check if post is working or not and it was working. But problem is occurring when I'm trying it with a persistent database (MongoDB).
mongoose.js (For connection with database)
//requiring mongoose to set up connection with database
const mongoose = require('mongoose');
//setting up connection
mongoose.connect('mongodb://localhost:27017/tasks_db', {useNewUrlParser: true, useUnifiedTopology: true});
//to check if the connection is successful or some error occured
const db = mongoose.connection;
db.on('error', console.error.bind(console, "!! Error setting up connection with database !!"));
db.once('open', function() {
console.log("Connection with database is successful!");
});
task.js (Containing the schema)
//requiring mongoose
const mongoose = require('mongoose');
//creating the schema for the document of collection
const taskSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
due_data: {
type: Date,
required: true,
get: value => value.toDateString()
},
category: {
type: String,
}
});
//compiling our schema into a model (a class for interacting with MongoDB) (an instance of model is called a document)
const Task = mongoose.model('Task', taskSchema);
module.exports = Task;
home.ejs (containing the view)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Your TO-DO List</title>
<script src="https://kit.fontawesome.com/fcba9de078.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="/css/style.css" />
</head>
<body class="toggler">
<!-- The main box containing the list and the form to add or remove item -->
<div id="todo-box-div" class="flex-row sizi">
<!-- div containing form for adding items to todo-list -->
<div id="todo-form-div" class="flex-column sizi">
<!-- div header -->
<h1>Do It!</h1>
<!-- form for adding items -->
<form action="/new-task" method="POST" id="to-do-form" class="flex-column up-down">
<input id="title" name="title" class="bottom-b font-4" type="text" placeholder="I have to do this..." required />
<!-- <textarea id="description" class="bottom-b font-4" type="text"></textarea> -->
<!-- date and category will be inline for bigger widths -->
<div id="input-inline" class="flex-row">
<input id="date" name="due_date" min="2020-07-20" class="bottom-b font-2" type="date" required />
<select id="category" name="category" class="bottom-b font-2 dropdown" type="text">
<option value="default" selected disabled>Choose a category</option>
<option value="Work">Work</option>
<option value="College">College</option>
<option value="Home">Home</option>
<option value="Group">Group</option>
</select>
</div>
<!-- button for adding item -->
<button type="submit" class="font-4" id="add"><i class="fas fa-plus"></i>Add to list</button>
</form>
</div>
<!-- div containing list items (scrollable) and button to delete items -->
<div id="todo-list-div" class="flex-column sizi">
<!-- button for deleting items -->
<button type="submit" class="font-4" id="delete"><i class="far fa-trash-alt"></i>Done</button>
<!-- list containing todo items -->
<ul>
<% for(let a of tasks) { %>
<li>
<div class="list-item">
<input type="checkbox" class="pointer" />
<div class="name-date font-3">
<p><%= a.title %></p>
<p><i class="far fa-calendar-alt"></i><%= a.due_date %></p>
</div>
<div id="redundant"></div>
<div class="categ-button font-2 disp"><%= a.category %></div>
</div>
</li>
<% } %>
</ul>
</div>
</div>
<script src="/js/script.js"></script>
</body>
</html>
Note: The form is in the todo-form-div under todo-box-div.
Example error:
Here, if you see it is printing "Error while posting" on submitting the form. The req.body is getting printed. This error message is in the error handling of app.post() method in index.js.
I was stuck for too long and decided to post it here and get some guidance. Please help me out with this.
Try the following in post method instead of Task.create() and let me know if it works
const task = new Task({title: "Work",
due_date: "2012-12-13",
category: "Work"})
task.save();

How to combine schema model with file upload in Node.js and MongoDB?

Good day everyone, I am building a web application to store employee information in a local database. I have written the necessary code so that the client can input the required information such as Name, email, phone number etc. via a form and save it to MongoDB. Now I would like to add a file upload feature so that documents can be uploaded alongside employee information, such as insurance policies, passport copies etc. I am struggling to find a way to implement this as a lot methods online show implementations of CRUD and file uploads separately. Is there anyone experienced who would be able to suggest an implementation approach? I'm new to Node dev and not familiar with the vast selection of available frameworks. So far I have the following set up:
Frameworks used: Express, Mongoose, Express-Handlebars (view engine), Bootstrap
employee.Model:
const mongoose = require('mongoose');
const mongoURI = 'mongodb://localhost:27017/testDB'
const conn = mongoose.createConnection(mongoURI, {useNewUrlParser: true});
Schema = mongoose.Schema;
var employeeSchema = new Schema({
fullName: {
type: String,
required: true
},
email: {
type: String
},
mobile: {
type: String
},
city: {
type: String
}
});
const Employee = conn.model('Employee', employeeSchema);
module.exports = Employee;
Employee Controller:
const mongoose = require ('mongoose');
const express = require ('express');
var router = express.Router();
const Employee = require('../models/employee.model');
router.post('/', (req, res) => {
insertRecord(req, res);
});
function insertRecord (req, res) {
var employee = new Employee();
employee.fullName = req.body.fullName;
employee.email = req.body.email;
employee.mobile = req.body.mobile;
employee.city = req.body.city;
employee.save((err, doc) =>{
if (!err)
res.redirect('employee/list');
else {
console.log('Error during record insertion: ' + err);
}
});
}
Handlebars View:
<h3>{{viewTitle}}</h3>
<form action="/employee" method="POST" autocomplete="off">
<div class="form-group">
<label>Full Name</label>
<input type="text" class="form-control" name="fullName"
placeholder="Full Name">
</div>
<div class="form-group">
<label>Email</label>
<input type="text" class="form-control" name="email"
placeholder="Email">
</div>
<div class="form-row">
<div class="form-group col-md-6">
<label>Mobile</label>
<input type="text" class="form-control" name="mobile"
placeholder="Mobile">
</div>
<div class="form-group col-md-6">
<label>City</label>
<input type="text" class="form-control" name="city"
placeholder="City">
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-info"><i class="fa fa-
database"></i> Submit</button>
</div>
</form>
Uploaded files are inputs just like others, they just need the specific enctype="multipart/form-data" attribute on the HTML side, and a proper handling on the server.
And easy-to-grasp demonstration using Multer (based on their own examples actually):
const upload = require('multer')({dest: 'uploads/'}); // npm i multer
const fileUploadMiddleware = upload.fields({
{name: 'resume', maxCount: 1},
{name: 'insurance', maxCount: 4}
});
router.post('/', fileUploadMiddleware, (req, res) => {
insertRecord(req, res);
});
function insertRecord(req, res) {
...
console.log(req.files.resume[0].mimetype); // this is resume file type
console.log(req.files.insurance[0].path); // this is first insurance file path
console.log(req.body.fullName); // this still works
}

node.js not retrieving any data from mongodb

I am a beginner to node.js and trying to learn how to get data from mongodb to pass through node.js and display on the page.
I am learning it from a tutorial so follow those methods here.
https://www.youtube.com/watch?v=dSQ1CYLHWYM&index=6&list=PL55RiY5tL51rajp7Xr_zk-fCFtzdlGKUp
When I restart the server and load localhost it gets stuck and doesn't move forward and also does not show any errors in the terminal or the database or the console.
I am not sure why it is not showing any data in the view. My mongodb is working and listening to port 27017 and also if I go to mongod and do a db.products.find() I get to see all the data. Also if I just do it normally like var products = Product.find() it shows some data so basically there should be data coming in.
var express = require('express');
var router = express.Router();
var Product = require('../models/product');
/* GET home page. */
router.get('/', function(req, res, next) {
Product.find(function(err, docs){
console.log(docs);
var productChunks = [];
var chunkSize = 3;
for( var i= 0 ; i < docs.length ; i+= chunkSize) {
productChunks.push(docs.splice(i, i + chunkSize));
}
res.render('shop/index', { title: 'Shopping Cart' , products : productChunks});
});
});
module.exports = router;
And here is the Schema for the db
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var schema = new Schema({
imagePath : {type : String, required: true},
title : {type : String, required: true},
description : {type : String, required: true},
price : {type : String, required: true},
});
module.exports = mongoose.model('Product', schema);
Here is the index.hbs
{{# each products}}
<div class="row">
{{# each this}}
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img class="img-responsive" src="{{this.imagePath}}" alt="...">
<div class="caption">
<h3>{{this.title}}</h3>
<p>{{this.description}}</p>
<div class="clearfix">
<div class="pull-left">${{this.price}}</div>
Add to cart
</div>
</div>
</div>
</div>
{{/each}}
</div>
{{/each}}
So I am not really sure how to tackle this problem. Since my local host is getting stuck, even if I restart the DB and server it still doesn't work.
Problem was that my app.js file was not completely configured well. I forgot to connect to mongoose. I solved the problem already.
Thanks everyone who commented on this.

Resources