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
Related
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);
})
}
I'm attempting to make a fetch call to News API and populate my Articles collection in Mongo DB with the data I fetch. I have two files: articles.js, and article.js. - my schema looks like the following:
// Article.js
const ArticleSchema = new Schema({
title: {
type: String,
required: true
},
author: {
type: String,
required: true
},
description: {
type: String,
required: true
},
url: {
type: String,
required: true
},
datePublished: {
type: String,
required: true
},
source: {
type: String,
required: true
}
})
In articles.js, this is what my route looks like. My logic is that I make my fetch call, wait for the JSON to return, then iterate thru that json and map all the information I need to new story objects. Once I have those objects - I want to create a new instance of an Article for each, then post them to my Articles collection in Mongo DB.
/ #route POST /articles -> adds new instance of an article to the database
router.post('/', async (req, res) => {
try {
const res = await fetch('https://newsapi.org/v2/top-headlines?country=us&category=entertainment&apiKey=63c967f7cbd84c11b263b4e4758f1693');
const data = await res.json();
data.articles.forEach(article => {
const storyData = {
title: article.title,
author: article.author,
description: article.description,
url: article.url,
datePublished: article.publishedAt,
source: article.source.name
}
// console.log(storyData)
new Article(storyData)
.save()
})
} catch (err) {
console.error(err.message)
res.status(400).json({ message: err.message })
}
})
After my forEach loop, I get the objects like so:
{
title: `'Matrix 4' Style "Shifted" From Original Trilogy, Says Neil Patrick Harris - Hollywood Reporter`,
author: 'Ryan Parker',
description: 'The actor, who appears in the fourth installment, called the upcoming film "ambitious."',
url: 'https://www.hollywoodreporter.com/heat-vision/matrix-4-style-shifted-from-original-trilogy-says-neil-patrick-harris',
datePublished: '2020-09-16T17:54:26Z',
source: 'Hollywood Reporter'
}
I'm able to get the objects I'd like with the data I need, however when I attempt to call .save(), I receive validation error similar to the following:
"ValidationError: article validation failed: author: Path author is required."
I'm thinking that it may have to do with the fact that when I make post to the DB, the request should list something along the lines of "title: req.body.title", etc... Any thoughts on what could be causing this? My goal is to simply post these to the DB as I create them. Thanks!!!
I am working on a express app with mongoose.
the .find method is working in other route but inside my blogs route, it is not working.
Here is my mongoose model:
const mongoose = require('mongoose');
let BlogSchema = new mongoose.Schema({
title: {type: String, unique: true, required: true},
body: {type: String},
category: String,
permalink: String,
date: {type: Date, default: Date.now},
image: {type: String},
imageId: String,
tags:[{type: String}],
author: {
id: {
type: mongoose.Schema.Types.ObjectId,
ref: "User"
},
username: String
}
});
let Blog = mongoose.model('Blog', BlogSchema);
module.exports = Blog;
and here is my router.get :
//SHOW ROUTE
router.get('/blog/:category/:permalink', (req,res)=>{
console.log(req.params) //{ category: 'travel', permalink: 'why-travel-to-places' }
Blog.find({category: req.params.category,permalink: req.params.permalink}, (err, foundPost)=> {
if (err){
console.log(err)
} else {
console.log(foundPost) // []
res.render('blog/show', {post: foundPost});
}
});
});
As you can see, I console.log req.params and foundPost .
req.params result is { category: 'travel', permalink: 'why-travel-to-el-nido' } and foundPost is an empty array []
Now I looked at mongo using db.blogs.find({category: "travel"}).pretty() and it found it. But inside my show route ,it is not finding it?
I looked up on other questions related to my problem and someone said that perhaps it has a problem with schema, but in my case, it's not.
my .find() is working in in other routes but in it's not working in this route.
Did I miss something, please help. Thank you
I'm pretty sure that the .find() is working correctly, but is not finding any document in the database with that query criteria. Note that in the route code you are querying { category: 'travel', permalink: 'why-travel-to-el-nido' }, i.e that the matched Blog document must have the fields category: 'travel' AND permalink: 'why-travel-to-el-nido', but when you look at Mongo using db.blogs.find({category: "travel"}).pretty() you are only looking for Blog documents that have {category: "travel"}, but no restriction for the permalink field.
Please, search again in Mongo using db.blogs.find({category: "travel", permalink: "why-travel-to-el-nido"}).pretty() to simulate the same query from the route, and see if you can find any document that matches that criteria.
My guess is that you won't find any, so the mongoose .find() is returning an empty array, meaning "no matches".
Edit: I just saw the comment from Neil Lunn, and it might be possible that the mongoose configuration is not pointing to the right database. Follow his instructions to make sure you are querying to the collection you want.
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}, `) )
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!