How to bind array of values to nodeJs model? - node.js

I am developing RESTful API.
Model
var productsSchema = new Schema({
productName:{type: String, required: true},
productDescription: {type: String, required: true},
produtThumbnail:{type: String},
productStock: [
{
size: {type: Number, required: false},
price: {type: Number, required: false}
}],
productTags:[{
tag: {type: String, required: false}
}]
});
POST Method
router.post('/api/new-product',upload.any(),function(req, res, next){
console.log(req.body);
if(req.files){
req.files.forEach(function(file){
var filename = (new Date()).valueOf() + '-' + file.originalname;
fs.rename(file.path,'public/images/'+ filename, function(err){
if (err) throw err;
console.log('file Uploaded');
//Save to mongoose
var product = new Products({
productName: req.body.productName,
productDescription: req.body.productDescription,
size: req.body.productStock.size,
productThumbnail: filename
});
product.save(function(err, result){
if(err){}
res.json(result);
});
});
});
}
}) <br/>
Problem:
I am able to bind object data to model, but I don't know how to bind array-data to model.
For example
var product = new Products({
productName: req.body.productName,
productDescription: req.body.productDescription,
size: req.body.productStock.size,// This line doesn't work
productThumbnail: filename
});
size:req.body.productStock doesn't work
So, How can I bind array-data to model, and then save it to mongodb?
Please help..

Just change it to type array
var productsSchema = new Schema({
merchantId: {type: String, required: false},
produtThumbnai:{type: String},
productStock: {type: Array},
productTags:{type: Array}
});
It Works!!

Maybe it's just because of a typo, because your Schema looks OK. Change this:
var product = new Products({
// ...
size: req.body.productStock.size,
// ...
});
To this:
var product = new Products({
// ...
productStock: req.body.productStock,
// ...
});
For this to work you should be passing your productStock as an array of objects from your POST request (!)
Otherwise it's a bit difficult to offer you more help, since we are unaware of what req.body actually is.
EDIT
To check if the above works (and assuming you are passing productStock as a whole array of objects from Postman/Curl/whatever), do the following and paste the result here:
product.productStock.foreach( (product, idx) => console.log(`(${idx}):${product.id}, `) )

Related

How do I use MongoDB data with D3 and Node?

Using Node, Express, Mongoose, and MongoDB, I'm trying to send a GET request to MongoDB and then use the data as an object for a D3 graph. I have the code for the graph in a separate js file. How do I send the data to that file?
Here are the basic Schemas I'm using:
var hikeSessionSchema = new mongoose.Schema({
hike_name: {type: String, required: true},
hike_date: {type: String, required: true},
mileage: {type: Number, required: true},
duration: {type: String, required: true},
elevation_gain: {type: Number, required: true},
city: {type: String, required: true},
location: {type: String, required: true},
notes: String
})
var hikerSchema = new mongoose.Schema({
username: {type: String, required: true},
log: [hikeSessionSchema]
})
var HikeSession = mongoose.model('HikeSession', hikeSessionSchema)
var Hiker = mongoose.model('Hiker', hikerSchema)
So I want to find the user by ID, then get an array of the user's HikeSessions. And I want to move that data to a js doc to make a d3 graph (I've already made the d3 app on CodePen but connected it to Google Sheets before).
I think the GET request should be something like this, but I don't know what to do with the result. The path will probably change:
app.get('/:id', (req, res) => {
const id = req.params.id;
Hiker.findById(id)
.then(result => {
//What goes here?
})
.catch(err => {
console.log(err);
})
}
After I get the data into the d3 doc, I'm not sure what challenges I'll run into with rendering it.
Step 1:
Define and export your d3_generator(input) function in d3.js:
const d3_generator = (input) => {
/// (Your logic)
}
module.exports = { d3_generator };
Step 2
Import d3_generator function from d3.js in your controller and use it after you got result from MongoDB:
const { d3_generator } = require('./d3');
...
app.get('/:id', (req, res) => {
const id = req.params.id;
Hiker.findById(id)
.then(result => {
let generated_d3 = d3_generator(result.log);
})
.catch(err => {
console.log(err);
})
}

Recommendations on handling cast errors? NodeJS | MongoDB

I'm essentially building a form app that lets the user update their information. All the form data is stored in MongoDB. I'm also using pug templates to render my pages.
However, I'm getting some funky behavior with the code below. When I click update details on my pug template for updating, terminal shows: { CastError: Cast to ObjectId failed for value "mylist" at path "_id" for model "Photo"
My page just keeps loading and says waiting for local host. The weird thing is when I go back to my homepage and click refresh, I see the updated details on the page and in MongoDB. Same thing goes when I try to post a new entry. I think it's because of the below specific snippets of code...
router.get('/:itemid', (req, res, next)=>{
Photo.findOne({'_id': req.params.itemid})
.then((photo)=>{
res.render('update', {
item: photo
});
}).catch((err)=>{
if (err){
console.log(err);
}
});
});
router.post('/:itemid', (req, res, next)=>{
Photo.findOne({'_id': req.params.itemid})
.then((photo)=>{
var data = {
destination: req.body.destination,
description: req.body.description
}
photo.set(data);
photo.save().then(()=>{
res.redirect('/mylist');
});
}).catch((err)=>{
if (err){
console.log(err);
}
});
});
pug template below:
block content
h1 Updating Your Listing
.row
.col-sm-3
p Destination: #{item.destination}
p Description: #{item.description}
img(src=item.imageurl, width="250")
form(method='POST', action='/mylist/' + item._id)
.form-group
label(for='destination') Destination:
input#name.form-control(type='text', value=item.destination
name='destination')
.form-group
label(for='description') Description:
input#email.form-control(type='text',
value=item.description name='description')
button.btn.btn-primary(type='submit') Update Listing
Information
Schema:
var schema = new Schema ({
mimetype: {type: String, required: true},
filename: {type: String, required: true},
imageurl: {type: String, required: true},
description: {type: String, required: true},
destination: {type: String, required: true},
createdAt: {type: Date},
updatedAt: {type: Date}
});
// export models
module.exports = mongoose.model("Photo", schema);
Your route handler accepts POST /:itemid, but your form sends POST /mylist/:itemid. That results in express parsing mylist as your id. Change either your route to /mylist/:itemid or remove from your form /mylist

Mongoose pre-save hook fires, but does not persist data

I am encountering a problem where my Mongoose pre.save() hook is firing, but the attribute does not get saved to the database. I have been searching for a long time without finding an answer.I found this thread, and the behaviour I am experiencing is very similiar, but OP's problem is related to the context of this, whereas I seem to have a different problem.
Here is my models.js:
'use strict';
const mongoose = require("mongoose");
const slugify = require("slugify");
let Schema = mongoose.Schema;
let BlogPostSchema = new Schema({
title: {
type: String,
required: true
},
createdAt: {type: Date, default: Date.now},
updatedAt: {type: Date, default: Date.now},
author: String,
post: {
type: String,
required: true
}
});
BlogPostSchema.pre('save', function(next) {
this.slug = slugify(this.title);
console.log(this.slug);
next();
});
// Passed to templates to generate url with slug.
BlogPostSchema.virtual("url").get(function() {
console.log(this.slug);
console.log(this.id);
return this.slug + "/" + this.id;
});
BlogPostSchema.set("toObject", {getters: true});
let BlogPost = mongoose.model("BlogPost", BlogPostSchema);
module.exports.BlogPost = BlogPost;
And here is the relevant lines in the router file index.js:
const express = require('express');
const router = express.Router();
const BlogPost = require("../models").BlogPost;
// Route for accepting new blog post
router.post("/new-blog-post", (req, res, next) => {
let blogPost = new BlogPost(req.body);
blogPost.save((err, blogPost) => {
if(err) return next(err);
res.status(201);
res.json(blogPost);
});
});
I am able to save the blog post to the database, and my console.log's correctly prints out the slug to the console. However, the this.slug in the pre-save hook does not get persisted in the database.
Can anybody see what the problem is here? Thank you so much in advance.
Mongoose will act according to the schema you defined.
Currently, your schema does not contain s filed named slug.
You should add a slug field to your schema.
Changing your current schema to something like this should work:
let BlogPostSchema = new Schema({
slug: String,
title: {
type: String,
required: true
},
createdAt: {type: Date, default: Date.now},
updatedAt: {type: Date, default: Date.now},
author: String,
post: {
type: String,
required: true
}
});

While creating api with nodejs, reference error: schema is not defined

I want to reach information with get method on Postman. But whenever i "localhost:3000/api/mekanlar/mekan's objectid", i get reference error "Mekan is not defined". Here is my mekansema.js file in /app_api/models.
var mongoose = require('mongoose');
var saatSema = new mongoose.Schema({
gunler: {type: String, required: true},
acilis: String,
kapanis: String,
kapali: {type: Boolean, required: true}
});
var yorumSema = new mongoose.Schema({
ad: String,
puan: {type: Number, required: true, min:0, max:5},
yorumMetni: String,
saat: {type: Date, default: Date.now}
});
var mekanSema = new mongoose.Schema({
ad: {type: String, required: true},
adres: String,
puan: {type: Number, default:0, min:0, max:5},
imkanlar: [String],
mesafe: {type: [Number], index:'2dsphere'},
saat: [saatSema],
yorumlar: [yorumSema]
});
mongoose.model('Mekan', mekanSema, 'Mekanlar');
and mekanlar.js file in /app_api/controllers
var mongoose = require('mongoose');
var mekan = mongoose.model('Mekan');
var jsonCevapYolla = function(res, status, content){
res.status(status);
res.json(content);
};
module.exports.mekanGetir = function(req, res){
if (req.params && req.params.mekanid){
Mekan
.findById(req.params.mekanid)
.exec(function(hata, mekan){
if(!mekan){
jsonCevapYolla(res, 404, {
"mesaj" : "mekanid bulunamadı."
});
return;
}
else if(hata){
jsonCevapYolla(res, 404, hata);
return;
}
jsonCevapYolla(res, 200, mekan);
});
}
else{
jsonCevapYolla(res, 404, {
"mesaj" : "istekte mekanid yok"
});
}
};
and this is index.js in /app_api/routes.
var express = require('express');
var router = express.Router();
var ctrlMekanlar = require('../controllers/mekanlar');
var ctrlYorumlar = require('../controllers/yorumlar');
//Mekan Rotaları
//router.get('/mekanlar', ctrlMekanlar.mekanlariListele);
//router.post('/mekanlar', ctrlMekanlar.mekanEkle);
router.get('/mekanlar/:mekanid', ctrlMekanlar.mekanGetir);
//router.put('/mekanlar/:mekanid', ctrlMekanlar.mekanGuncelle);
//router.delete('/mekanlar/:mekanid', ctrlMekanlar.mekanSil);
//Yorum Rotaları
//router.post('/mekanlar/:mekanid/yorumlar', ctrlYorumlar.yorumEkle);
//router.get('/mekanlar/:mekanid/yorumlar/:yorumid', ctrlYorumlar.yorumGetir);
//router.put('/mekanlar/:mekanid/yorumlar/:yorumid', ctrlYorumlar.yorumGuncelle);
//router.delete('/mekanlar/:mekanid/yorumlar/:yorumid', ctrlYorumlar.yorumSil);
module.exports = router;
it's difficult to see where the problem is, since you don't provide a stack trace. but I think at this line:
Mekan
.findById(req.params.mekanid)
Mekan should be mekan.

Retrieve Array in Subdocument MongoDB

I have a Users model structure somewhat like this:
const userSchema = new mongoose.Schema({
email: { type: String, unique: true },
password: String,
todosDo: [models.Do.schema],
}
And the child "Do" schema somewhat like this (in a different file):
const doSchema = new mongoose.Schema({
name: {type: String, default : ''},
user: {type: mongoose.Schema.ObjectId, ref: 'User'},
createdAt: {type : Date, default : Date.now}
});
And I'm trying to figure out how to retrieve the todosDo array for the signed in user. This is what I've got so far:
// Get all "Do" todos from DB
// Experimenting to find todos from certain user
User.findById(req.user.id, function(err, user){
if(err){
console.log(err);
} else {
doTodos = user.todosDo, // this obviously doesn't work, just an idea of what I was going for
console.log(doTodos);
finished();
}
});
Am I referencing the child/parent wrong or am I just not retrieving the array right? Any help is greatly appreciated!
As far I guess you may want to edit as raw js objects so you need to use lean() function. without using lean() function user is mongoose object so you can't modify it.
can try this one:
User.findById(req.user.id)
.lean()
.exec(function (err, user) {
if(err){
console.log(err);
return res.status(400).send({msg:'Error occurred'});
}
if(!user) {
return res.status(400).send({msg:'User Not found'});
}
doTodos = user.todosDo;
console.log(user.todosDo); // check original todos
console.log(doTodos);
return res.status(200).send({doTodos : doTodos }); // return doTodos
});
and to refer child schema in parent schema from different model you can access a Model's schema via its schema property.
say in doSchema.js file
const doSchema = new mongoose.Schema({
name: {type: String, default : ''},
user: {type: mongoose.Schema.ObjectId, ref: 'User'},
createdAt: {type : Date, default : Date.now}
});
module.exports = mongoose.model( 'DoSchema', doSchema );
in user.js file
var DoModel = require('./doSchema');// exact path
const userSchema = new mongoose.Schema({
email: { type: String, unique: true },
password: String,
todosDo: [DoModel.schema],
}
Thanks for your help everybody! My problem was that I needed to push all the newly created todos in the post route to todosDo, so then I could retrieve them at the get route. Everything's working now!

Resources