MongoDB req.body Issue - node.js

I have a very simple Mongo set up as shown below. This works perfectly to get data from an input field and save the data. All working.
My Question: How would I go about looping through the jobs variable on the front end and set the data up so that it would work with my model. Somehow I would need to get it into inputs so I can req.body?
Data:
var jobs = [
{
name: "Accountant"
salary: 0,
}, {
name: "Actor"
salary: 0,
}, {
name: "Actuary"
salary: 0
}]... + hundreds more...
My Mongo Schema:
var JobSchema = new mongoose.Schema({
name: String,
salary: Number
});
module.exports = mongoose.model('jobs' , jobSchema)
My post route:
router.post('/register', function(req, res) {
var job = ({
name: req.body.name,
salary: req.body.salary,
})
Form to post:
<form action="/register" method="post">
<textarea class='jobnames' type="text" name="name" placeholder="name"> </textarea>
<textarea class='2' type="number" name="salary" placeholder="salary"> </textarea>
<button >Submit</button>
</form>

You can try it using the insertMany() query .
req.body = [
{
name: "Accountant",
salary: 0,
},
{
name: "Actor",
salary: 0,
},
{
name: "Actuary",
salary: 0
}
]
db.collection.insertMany(req.body);
With the help of this query , you can insert multiple documents at a time .
unique id i.e., _id will be automatically generated .
For more information about insertMany() visit the official document

You can just create it with the array itself, i.e. pass the array jobs in the post request. For example:
// set up the model using the schema
var Job = mongoose.model('Job', JobSchema);
Job.create(req.body)
.then(records => console.log('created records', JSON.stringify(records, null, 2))
see Model.create

Related

Vuejs- How to show name values in a <v-select> but send the ID in the axios POST request

EDIT: I fixed it by adding the return-object prop to v-select
When I add a student to a database from a vuetify form, I want to be able to assign them a course. But the course has to be in a list of available courses (also in the db). I managed to do that and show all the available courses in a dropdown menu.
However, when I add the new student to the database, it sends the name of the course but not the ID of the course, so the database doesn't recognize it. I would like to link the name of the course from the v-select dropdown menu to its object ID and send the ID in the POST request.
My form component:
<v-select
:items="courses"
v-model="Courses"
item-value="name"
item-text="name"
label="Available courses"
prepend-icon="folder"
>
<template v-slot:item="{ item, attrs, on }">
<v-list-item
v-bind="attrs"
v-on="on"
>
<v-list-item-title
:id="attrs['aria-labelledby']"
v-text="item.name"
></v-list-item-title>
</v-list-item>
</template>
</v-select>
Where I store all the available courses:
computed: {
courses() {
return this.$store.state.courses;
},
The axios POST method:
methods: {
async addItem(){
const response = await axios.post("http://localhost:4000/api/student", {
name: this.name,
Courses: this.courses,
});
this.items.push(response.data);
this.name = "";
this.courses ="";
},
},
My mongoDB model:
const Student = mongoose.model(
"Student",
new mongoose.Schema({
name: String ,
Courses:
{
type: mongoose.Schema.Types.ObjectId,
ref:"id"
},
})
);
module.exports = Student;
The Course model:
const Course = mongoose.model(
"Course",
new mongoose.Schema({
name: String ,
available: {type:Boolean , default :true} ,
})
);
module.exports = Course;
Need more information on how each course object looks, and your data, but essentially, set the item-value prop to the item's object ID, and under the addItem function,
async addItem(){
const response = await axios.post("http://localhost:4000/api/student", {
id: this.courseId,
Courses: this.courses,
});
this.items.push(response.data);
this.courseId = "";
this.courses ="";
}
EDIT:
It might be a good idea to name your variables better, e.g.
// in your v-select
v-model="selectedCourse"
// in your addItem function
Course: this.selectedCourse
or
Courses: this.selectedCourses
If you just want to get id of the course in v-model of v-select, You can simply use item-value="id" instead of item-value="name".
Live Demo :
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: () => ({
selectedCourse: null,
courses: [{
id: 1,
name: 'Course 1'
}, {
id: 2,
name: 'Course 2'
}, {
id: 3,
name: 'Course 3'
}, {
id: 4,
name: 'Course 4'
}, {
id: 5,
name: 'Course 5'
}],
}),
methods: {
getSelected() {
console.log(this.selectedCourse) // ID of the selected course
}
}
})
<script src="https://unpkg.com/vue#2.x/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#2.6.6/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify#2.6.6/dist/vuetify.min.css"/>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons"/>
<div id="app">
<v-app id="inspire">
<v-container fluid>
<v-select
:items="courses"
v-model="selectedCourse"
label="Available courses"
prepend-icon="folder"
item-value="id"
item-text="name"
#change="getSelected"
></v-select>
</v-container>
</v-app>
</div>

add a "add to cart" feature using mongodb and node js

I've been trying many things and couldn't write the code for the "add to cart" feature. Can you please help me in doing this?
Here is the cart model:
var cartSchema = new mongoose.Schema({
owner: {type: mongoose.Schema.Types.ObjectID, ref: 'User'},
totalPrice: {type: Number, default: 0},
items: [{
item: {type: mongoose.Schema.Types.ObjectID, ref: 'Product'},
qty: {type: Number, default: 1},
price: {type: Number, default: 0}
}]})
Here is the product model:
var productSchema = new mongoose.Schema({
category: String,
name: String,
price: Number,
image: String,
description: String,
stock: Number,
reviews: [
{
type: mongoose.Schema.Types.ObjectID, ref: 'Review'
}
]
})
Edit(detailed explanation):
step1: when I click on the add to cart button it should make a "get" request and these following things should happen:
get the id of the signed-in user i.e req.user._id
store the clicked product inside the items array in the cart model
based on the required quantity of the product it should calculate the price i.e qty*price and store it in "price" in the items array in the cart model
step2: when another product is added to the cart it should follow all the steps mentioned in step1 and in addition to that it should calculate the total price of the cart i.e. totalPrice = qty1xproduct1_price + qty2xproduct2_price + .... and store it in "totalPrice" in the cart model.
step3: when I click on view cart i.e. router.get("/cart"), this should take me to the cart and it should check for the signed-in user and show the cart which belongs to that user i.e. it should check for Cart.owner and show me all the details of the cart. Ex: (
product details in short
quantity
price= qty x price_per_product
In the end total price of all these products
)
edit 3:
Here is add to cart button:
<form action="/product/<%= product._id %>/addCart" method="POST">
<select name="quantity">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button>Add to cart</button>
</form>
Here is cart route:
router.post("/product/:id/addCart", async (req, res) => {
const quantity = req.body;
Product.findById(req.params.id, function(err, foundProduct){
if(err){
console.log(err);
}
const product = {
item: foundProduct._id,
qty: quantity,
price: foundProduct.price * quantity
}
Cart.owner = req.user._id;
Cart.itmes.push(product);
Cart.save();
res.redirect("/cart");
})
})
router.get("/cart", function(req, res){
Cart.find({owner: req.user._id}, function(err, userCart){
if(err){
console.log(err);
}
const pPrice = userCart.items.map(p => p.price);
const totalPrice = pPrice.reduce((a, b) => a + b, 0);
userCart.totalPrice = totalPrice;
userCart.save()
res.render("cart", {cart: userCart});
})
})
It shows Cannot POST /product/5f80569156202d0a624d35af/addCart
In order to help you, here's a quick example :
Simple HTML :
Quantity :
<select id="quantity">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button id="btnOK">OK</button>
In your front-end JS (I used jQuery because it's much simpler to write than plain JS) :
$("#btnOK").click( () => {
const quantity = Number( $("#quantity").val());
const productData = {
id : "123456",
quantity,
price : quantity * 20
}
$.post( "/product" , productData, result => {
console.log("Response from Node : ", result)
})
})
In your back-end JS :
router.post("/product", async (req, res) => {
const productData = req.body;
const result = await (new productModel(productData)).save();
res.send(result)
})
If you want to return the sum of the price of several items, you don't need an aggregation. You can just fetch the products and sum up their prices. For instance :
const idArray = ["1", "3", "18", "27"]
// This should return 4 products :
const products = await productModel.find({
_id: {
$in: idArray
}
})
.lean()
.exec()
const totalPrice = products
.map( p => p.price)
.reduce((a, b) => a + b, 0)
res.send(totalPrice)

How can I add/subtract data from a EJS template

I cant figure out how to substract data from an EJS template. This is my Schema:
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var InventorySchema = Schema({
name: [{type: String, required: true, unique: true}],
quantity: [Number],
code: [String],
price: [Number],
stock: [{type: Boolean, default: true}]
})
var Inventory = mongoose.model("Inventory", InventorySchema);
module.exports = Inventory;
The below is the main query to show all my data:
router.get("/", (req, res)=>{
InventoryModel.find({})
.then((inventory)=>{
console.log(inventory);
res.render("inventory/index", {inventory: inventory})
})
.catch((err)=>{
console.log(err);
})
})
And below is the form Where I want to add/subtract data from:
<div class="container">
<form action="/inventory" method="POST">
<label>Name</label>
<input type="text" name="itemName" placeholder="item name"><p/>
<label>Quantity</label>
<input type="number" name="quantity" placeholder="quantity"><p/>
<button>Create</button>
</form>
</div>
So here's what I'm trying to accomplish. Whatever number I enter in the quantity field, subtract that data from my mongodb database whenever I hit the create button (which is a POST)
Any help?
Thank you
You would need to do an update on the existing document and use the $inc operator.
Example:
# create query conditions and update variables
const conditions = { },
update = { $inc: { views: 1 }}; # inc accepts negative numbers
# update documents matching condition
Model.update(conditions, update)

Trying to add followers in Mongoose subarray

I'm learning node.js and I'm trying to figure out how to add users to a subarray in my schema. I'm basically doing a twitter-clone in order to learn how node works.
This is my UserSchema. I want to add users into the "following" field-array.
#Usermodel.js
var UserSchema = mongoose.Schema({
username: {
type: String,
index:true
},
password: {
type: String
},
email: {
type: String
},
name: {
type: String
},
facebook : {
id : String,
token : String
},
resetPasswordToken: {type: String},
resetPasswordExpires: {type: Date},
following: [{type: mongoose.Schema.Types.ObjectId, ref: 'User'}], <-- I want to add users here
posts : [{ type: mongoose.Schema.Types.ObjectId, ref: 'Post' }]
});
UserSchema.index({username: 'text'});
var User = module.exports = mongoose.model('User', UserSchema);
Further down in this file you will find my schema method for adding users into the "following" subarray:
#Usermodel.js
module.exports.addFollowers = function (req, res, next){
User.findOneAndUpdate({_id: req.user._id}, {$push: {following: req.body.id}})
};
I'm querying a route in order to call my schema function. It looks like this:
#routes.js
router.get('/follow', User.addFollowers);
In my ejs front-end, I try to call my schema function by sending a GET-request to my route:
#index.ejs
<ul>
<%results.forEach(function(element){%> <-- Here I'm looping over users
<% if(user.id != element.id) { %> <-- Not show if it is myself
<li>
<%=element.username%></a> <br>
<form action="/follow" method="GET"> <-- Call route form
<input type="hidden" name="id" value=<%=element._id%>>
<button type="submit">Follow</button> <-- Submit GET
</form>
</li>
<% } %>
<br>
<%});%>
</ul>
Not sure what to do from here. When I press the "Follow" button my site keeps loading. Couldn't find any posts here on stackoverflow that could help me more at this stage.
Anyone who knows what is wrong? Is this the right way to do it?
Make some changes in #Usermodel.js
module.exports.addFollowers = function (req, res, next){
User.findOneAndUpdate({_id: req.user._id}, {$push: {following: req.body.id}}, next)
};
Try this code.

How to save form input array in mongodb?

This is the form I am using :
<form method="post" enctype="multipart/form-data">
<label class="label">Class Name</label>
<label class="input">
<input type="text" name="class_name[]">
</label>
<label class="label">Grade</label>
<label class="input">
<input type="text" name="grade[]">
</label>
</form>
Below is the schema I am using :
var SchoolSchema = new mongoose.Schema({
classroom: [{
Name: {
type: String,
required: true
},
grade: {
type: Number,
default: 1
}
}]
});
Firstly I tried saving the data using below function :
var School = new mongoose.Schema.model('School');
exports.submit = function(req, res) {
var classRooms = [];
for (var i = 0; i < req.body.class_name.length; i++) {
classRooms.push({Name: req.body.class_name[i], grade: req.body.grade[i]});
}
School.create({classroom: classRooms}, function(err, school) {
...
});
};
It worked fine when there was only a single entry in the form But for multiple entries it enters all the entries in single document. For e.g if through form I enter
Name: ABC Grade:1
Name: EFG Grade:2
This data dets saved in data base as
classroom:[{Name:ABC,EFG, Grade:1,2}]
and it should be like
classroom:[{Name:ABC, Grade:1},{Name: EFG, Grade:2}]
I even try to change the function as below:
var School = new mongoose.Schema.model('School');
exports.submit = function(req, res) {
var classRooms = [];
for (var i = 0; i < req.body.class_name[0].length; i++) {
classRooms.push({Name: req.body.class_name[0][i], grade: req.body.grade[0][i]});
}
School.create({classroom: classRooms}, function(err, school) {
...
});
};
Now this worked fine for multiple entries, but when I enter a single entrie it didn't worked as expected. For e.g. If I enter following data through form,
Name: AB Grade: 2
It gets saved in the database as
classroom:[{Name:A,Grade:2 },{Name:B,Grade:1}]
Would anyone please let me know what I am doing wrong here and how to correct this. Thanks !!

Resources