Related
Im trying to create an API where users can create their fav movies and rate them.
So instead of creating a Movies array in user model, I created a Movie model with userId as an array. Now the logic is if there is a movie by the same name the new user is trying to create, it will not create a movie, rather it will push the userid and their rating. If there is no movie by that name it will create one. But I am stuck in that part. Any help will be hugely appreciated. Below im posting my code.
Movie model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const movieSchema = new Schema({
title: {
type: String,
required: true,
},
rating: [
{ type: Number, required: true, max: 5 },
],
userId: [
{
type: String,
},
],
});
const Movie = mongoose.model(
'Movie',
movieSchema
);
module.exports = Movie;
user model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const userSchema = new Schema({
name: {
type: String,
required: true,
},
age: {
type: Number,
required: true,
},
// list: {
// type: Array,
// default: [],
// },
});
const User = mongoose.model('User', userSchema);
module.exports = User;
movie route
const router = require('express').Router();
const User = require('../models/User');
const Movie = require('../models/Movies');
//creating a movie
router.post(
'/:id/createmovie',
async (req, res) => {
const { title, rating } = req.body;
const userId = req.params.id;
try {
const currentMovie = await Movie.findOne({
title,
});
if (currentMovie == null) {
const newMovie = new Movie({
title,
rating,
userId,
});
newMovie
.save()
.then((data) => res.json({ data }))
.catch((err) => {
res.status(400).json({ error: err });
});
}
currentMovie
.updateOne(
{ title },
{ $push: { userId, rating } }
)
.then((data) => res.json({ data }))
.catch((err) => {
res.status(400).json({ error: err });
});
} catch (err) {
console.log(err);
}
}
);
// router.post('/:id/createmovie', (req, res) => {
// const { title, rating } = req.body;
// const userId = req.params.id;
// Movie.findOne({ title }).then((data) => {
// console.log(data);
// res.json(data);
// if (data == null) {
// res.send('true');
// }
// res.send('false');
// if (data.title == title) {
// Movie.updateOne(
// { title },
// { $push: { userId, rating } }
// );
// }
// const newMovie = new Movie({
// title,
// rating,
// userId,
// });
// newMovie
// .save()
// .then((data) => res.json({ data }))
// .catch((err) => {
// res.status(400).json({ error: err });
// });
// });
// });
router.get('/getmovie', (req, res) => {
const { title } = req.body;
Movie.find({ title })
.then((data) => res.json(data[0].title))
.catch((err) => {
res.status(400).json({ error: err });
});
});
module.exports = router;
Change router.post function arguments
router.post(
'/:id/createmovie',
async (req, res) => {
const { title, rating } = req.body;
const userId = req.params.id;
try {
const currentMovie = await Movie.findOne({
title,
});
if (currentMovie == null) {
await Movie.insertOne({title ,rating, userId})
.
}
else{
await Movie.updateOne(
{ title },
{ $push: { userId, rating } }
)
}
} catch (err) {
console.log(err);
}
}
);
this is my first project in node js and i created an API that have get, delete, update, and post.
i tested GET and response 200 ok but POST is 400 bad request i don't know why ...
i tested this in postman and vue js too but same result
below is my code in nodeJs:
can someone please tell me what is the problem?
thanks in advance
//question.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const questionSchema = new Schema({
questionTitle: {
type: String,
required: true,
},
is_solver_selected : {
type: Boolean,
default : false,
},
reviewed: {
type: Boolean,
default : false,
},
question_file_path: {
type: String,
required: true
},
description : {
type : String,
required : true
},
solutions : [
{
type: Schema.Types.ObjectId,
ref:"Solution",
default : []
}
],
owner : {
type : Schema.Types.ObjectId,
ref : "User",
required : true
},
categories : [{
type : Schema.Types.ObjectId,
ref : "Category",
required : true
}],
answered: {
type: Boolean,
default : false,
},
budget : {
type : String,
required : true
}
}, { timestamps: true });
const Question = mongoose.model('Question', questionSchema);
module.exports = Question;
//questionApiController
const Category = require('../models/category');
const Question = require('../models/question');
const User = require('../models/user');
const validators = require('../validators');
let questionApiController = {
// Get a single question
get_question : async (req , res) => {
const id = req.params.id;
try {
const question = await Question.findById(id,(err, question) => {
if (err) return res.status(400).json({response : err});
res.status(200).json({response : question})
}).populate('owner', 'username').populate('categories').populate({
path : "solutions",
populate : {path : "solver_candidate" , select : "username"}});
} catch (err) {
res.status(400).json(err);
}
},
// Get all the questions
get_questions: async (req , res) => {
try {
const questions = await Question.find((err, questions) => {
if (err) return res.status(400).json({response : err});
res.status(200).json({response : questions})
}).sort({ createdAt: -1 }).populate('owner', 'username').populate('categories').populate({
path : "solutions",
populate : {path : "solver_candidate" , select : "username"}});
} catch (err) {
res.status(400).json(err);
}
},
// Create a question
create_question : async (req , res) => {
const {error} = validators.postQuestionValidation(req.body);
if(error) return res.status(400).json({ "response" : error.details[0].message})
try {
const question = await new Question(req.body);
User.findByIdAndUpdate(req.body.owner)
.then(result => {
result.questions.push(question._id)
result.save((err, categories) => {
if (err) return res.status(400).json({response : {error : err , explanation : " Error binding to the user !"}});
});
})
.catch(err => {
res.status(400).json({response: err });
});
req.body.categories.forEach(element => {
Category.findById(element).then(result => {
}).catch(err => {
res.status(400).json({response : err });
})
})
question.save((err, question) => {
if (err) return res.status(400).json({response : err});
res.status(200).json({response : " Question created Successfully"})
});
} catch (err) {
res.status(400).json(err);
}
},
// Delete question
delete_question : async (req , res) => {
const id = req.params.id;
var questionExist = false;
var userId ;
const question = await Question.findById(id).then(result => {
questionExist = true;
userId = result.owner;
}).catch(err => {
questionExist = false;
res.status(400).json({response : err });
});
if(questionExist){
try {
Question.findByIdAndRemove(id ,(err, question) => {
// As always, handle any potential errors:
if (err) return res.json({response : err});
// We'll create a simple object to send back with a message and the id of the document that was removed
// You can really do this however you want, though.
const response = {
message: "Question successfully deleted",
id: question._id
};
return res.status(200).json({response : response });
});
User.findByIdAndUpdate(userId)
.then(result => {
let pos = result.questions.indexOf(question._id);
result.questions.splice(pos,1);
result.save((err, categories) => {
if (err) return res.status(400).json({response : {error : err , explanation : "Error binding unbinding from the user"}});
});
})
.catch(err => {
res.json({response: err });
});
} catch (err) {
res.status(400).json(err);
}
}
else {
return res.status(400).send( { "response" : "A question with that id was not find."});
}
},
// Update question
update_question : async (req , res) => {
const id = req.params.id;
Question.findByIdAndUpdate(id,req.body,
function(err, result) {
if (err) {
res.status(400).json({response : err});
} else {
res.status(200).json({response : "Question Updated"});
console.log(result);
}
})
},
bind_question_to_solver : async (req , res) => {
const id = req.params.id;
Question.findByIdAndUpdate(id,{
solver : req.body.solver ,
response_file_path : req.body.response_file_path},function(err, result) {
if (err) {
res.status(400).json({response : err});
} else {
res.status(200).json({response : "Question Bind to Solver"});
//Update the user solver by adding the question id in its quesion array1
console.log(result);
}
})
},
// Get question's questions
get_question_categories : async (req , res) => {
const id = req.params.id;
try {
const question_categories = await Question.findById(id).populate("categories")
console.log(question_categories)
res.json(question_categories)
} catch (err) {
console.log(err);
res.json(err);
}
}
}
module.exports = questionApiController
//question controller
const Question = require('../models/question');
const question_index = (req, res) => {
Question.find().sort({ createdAt: -1 })
.then(result => {
res.render('index', { questions: result, title: 'All questions' });
})
.catch(err => {
console.log(err);
});
}
const question_details = (req, res) => {
const id = req.params.id;
Question.findById(id)
.then(result => {
res.render('details', { question: result, title: 'Question Details' });
})
.catch(err => {
console.log(err);
res.render('404', { title: 'Question not found' });
});
}
const question_create_get = (req, res) => {
res.render('create', { title: 'Create a new question' });
}
const question_create_post = (req, res) => {
const question = new Question(req.body);
question.save()
.then(result => {
res.redirect('/questions');
})
.catch(err => {
console.log(err);
});
}
const question_delete = (req, res) => {
const id = req.params.id;
Question.findByIdAndDelete(id)
.then(result => {
res.json({ redirect: '/questions' });
})
.catch(err => {
console.log(err);
});
}
module.exports = {
question_index,
question_details,
question_create_get,
question_create_post,
question_delete
}
sent request:
Post http://localhost:9000/questions/api/add
content-type: application/json
{
"description": "d",
"questionTitle": "ddd",
"categories":"ddd",
"question_file_path":"d.pdf",
"budget":"d",
"owner":"bla",
}
`error message': HTTP/1.1 400 Bad Request
SyntaxError: Unexpected token } in JSON at position 160
at JSON.parse ()
at parse (C:\Users\saad\Desktop\APi-master-nodejs\node_modules\body-parser\lib\types\json.js:89:19)
at C:\Users\saad\Desktop\APi-master-nodejs\node_modules\body-parser\lib\read.js:121:18
at invokeCallback (C:\Users\saad\Desktop\APi-master-nodejs\node_modules\raw-body\index.js:224:16)
at done (C:\Users\saad\Desktop\APi-master-nodejs\node_modules\raw-body\index.js:213:7)
at IncomingMessage.onEnd (C:\Users\saad\Desktop\APi-master-nodejs\node_modules\raw-body\index.js:273:7)
at IncomingMessage.emit (events.js:327:22)
at endReadableNT (_stream_readable.js:1327:12)
at processTicksAndRejections (internal/process/task_queues.js:80:21)
update:
tested on vue js app console logs
enter image description here
based on your updated post, i would start to fix the provided json. because as the response says, it is invalid. JSON does not have trailing comma at the end of the last entry.
{ "description": "d", "questionTitle": "ddd", "categories":"ddd", "question_file_path":"d.pdf", "budget":"d", "owner":"bla"}
would be fine.
Check why-body-parser-json-is-not-working-showing-syntaxerror-unexpected-token post, you have a similar problem.
You are sending , symbol after last field in the json object which is not expected by the body-parser when you are sending content-type: application/json
In questionSchema you have a field called categories which must be an array of ObjectIds but you are sending a string in the request body
categories : [{
type : Schema.Types.ObjectId,
ref : "Category",
required : true
}],
Good evening,
I have my model
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const widgetSchema = new Schema({
city: {
type: String
}
})
const userSchema = new Schema({
name: {
type: String,
},
password: {
type: String
},
widgets: [widgetSchema]
})
const User = mongoose.model('user', userSchema);
module.exports = User;
And my question is how can I add elements to the widget array?
Should I use an update or what?
I think, firstly I need to find user document:
app.post('/addwidget', async (req, res) => {
const { city } = req.body;
try {
const user = await User.findOne({"name": "1"});
}
catch(err){
console.log(err)
}
})
and thank what? Is there method like push or something like that?
Try this one :
try {
const user = await Research.findOneAndUpdate({ name: '1' }, { $push: { widgets: { city: 'viking' }} })
if (user) return user;
else return false;
} catch (error) {
console.log(error);
}
you can use $push or $addToSet to add new item to the widgets array :
app.post('/addwidget', async (req, res) => {
const { city } = req.body; //
try {
const user = await User.findOneAndUpdate({"name": "1"} , { $push: { widgets: city }});
}
catch(err){
console.log(err)
}
})
or :
app.post('/addwidget', async (req, res) => {
const { city } = req.body;
try {
const user = await User.findOneAndUpdate({"name": "1"} , { $addToSet : {widgets: city }});
}
catch(err){
console.log(err)
}
})
From the doc: Adding Subdocs to Arrays, you can use MongooseArray.prototype.push()
E.g.
app.post('/addwidget', async (req, res) => {
const { city } = req.body;
try {
const user = await User.findOne({ name: '1' });
user.widgets.push({ city: 'viking' });
await user.save();
} catch (err) {
console.log(err);
}
});
I want to find an existing document in MongoDB by its _id. Everything works except trying to edit existing just creates a new document with a new _id instead of updating the current. It seems that it skips if (this._id) { in the model file. Very frustrated because I can see the issue but cannot find a fix. Thanks in advance!
plant.js controller:
exports.getEditPlant = (req, res, next) => {
const editMode = req.query.edit;
if (!editMode) {
console.log('Not Edit Mode');
}
const dbId = req.params._id;
Plant.findById(dbId)
.then(plant => {
if (!plant) {
console.log('Err');
res.redirect('back');
}
res.render('account/edit-plant', {
pageTitle: 'Edit Plant',
path: '/account',
plant: plant,
edit: editMode
});
}).catch(err => {
console.log(err);
});
};
exports.postEditPlant = (req, res, next) => {
const updatedName = req.body.common_name;
const scientific_name = req.body.scientific_name;
const updatedImg = req.body.image_url;
const slug = req.body.slug;
const updatedPlant = new Plant(updatedName, scientific_name, updatedImg, slug, new ObjectId(id));
updatedPlant.addMyPlant()
.then(plant => {
res.redirect('home');
}).catch(err => {
console.log(err);
})
};
plant.js model:
const mongodb = require('mongodb');
const getDB = require('../util/database').getDB;
module.exports = class Plant {
constructor(common_name, scientific_name, image_url, slug, id) {
this.common_name = common_name;
this.scientific_name = scientific_name;
this.image_url = image_url;
this.slug = slug;
this._id = id;
}
addMyPlant() {
const db = getDB();
let dbOp;
if (this._id) {
dbOp = db
.collection('myplants')
.updateOne({ _id: new mongodb.ObjectId(this._id) }, { $set: this });
} else {
dbOp = db.collection('myplants').insertOne(this);
}
return dbOp
.then(result => {
})
.catch(err => {
console.log(err);
});
}
static getMyPlants() {
const db = getDB();
return db.collection('myplants')
.find().toArray()
.then(plants => {
return plants;
}).catch(err => {
console.log(err);
});
}
static findById(dbId) {
const db = getDB();
return db
.collection('myplants')
.find({ _id: new mongodb.ObjectId(dbId) })
.next()
.then(plant => {
return plant;
})
.catch(err => {
console.log(err);
});
}
}
You need to assign the known _id to the ObjectID outside of the query.
In your code, you instantiate a new ObjectID inside your query but the value you passed in is not found.
This is a simplified version of your class with tests:
const mongodb = require('mongodb').MongoClient;
const ObjectID = require('mongodb').ObjectID;
const url = "mongodb://localhost:27017/mydb";
class Plant {
constructor(name) {
this.name = name;
}
// this method pulls all the records for me to test results
getAll() {
mongodb.connect(url, { useUnifiedTopology: true }, (err, db) => {
if (err) throw err;
var dbo = db.db("mydb");
dbo.collection("plants").find({}).toArray(function (err, result) {
if (err) console.log(err);
console.log(result);
db.close();
});
})
}
// update single record
updateMyPlant() {
mongodb.connect(url, { useUnifiedTopology: true }, (err, db) => {
if (err) console.log(err);
console.log("Mongo connected...");
const dbo = db.db("mydb");
// if you know the _id
// instantiate a variable outside your query
// now const id is the same as the _id you wants to query
const id = ObjectID("5fd8a1100617b03d8c737da0");
const myquery = { "_id": id };
const newvalues = { $set: { "name": "Marlon Brando" }};
try {
dbo.collection("plants").updateOne(myquery, newvalues, (err, res) => {
if (err) console.log(err);
console.log("update result", res.result, res.upsertedId);
db.close();
})
}
catch (e) {
console.log(e);
}
})
}
}
// test
const plant = new Plant("Alexa");
plant.updateMyPlant();
plant.getAll();
module.exports = Plant;
/**
* Logs:
* Mongo connected...
update result {
n: 1,
nModified: 1,
ok: 1
}
null
[{
_id: 5 fd8a1100617b03d8c737da0,
name: 'Marlon Mickey',
scientific_name: 'Brittain'
}]
*/
As you can see the _id is retained while the properties you want to change are updated.
See more info about ObjectID here
exports.clearHours = (req, res, next) => {
Hour
.find({ user: req.body.userId })
.then(hour => {
for (let i=0;i<hour.length;i++) {
hour[i].hours = 0;
}
return hour.save()
})
.then(result => {
res.status(200).json({message: 'Working hours have been successfully updated.'});
})
.catch(err => {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
})
};
I am trying to save the formatted array on the database and I get this error. The updated code is passed properly but when I am trying to save the array it comes up with this error. Any ideas why?
This is my hour model:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const hourSchema = new Schema ({
day: {
type: String,
required: true
},
hours: {
type: Number,
required: true
},
user: {
type: Schema.Types.ObjectId,
ref: 'User',
required: true
}
});
module.exports = mongoose.model('Hour', hourSchema);
It seems you are fetching the document into memory and re-setting the hour field to 0, better you can run an update query into the database itself.
On top require mongoose -
const mongoose = require('mongoose');
Below is clearHours method refactored.
exports.clearHours = async (req, res, next) => {
try {
const query = {
user: mongoose.Types.ObjectId(req.body.userId)
};
const update = {
$set: {
hours: 0
}
};
await Hour.update(query, update).exec();
res.status(200).json({message: 'Working hours have been successfully updated.'});
} catch (err) {
if (!err.statusCode) {
err.statusCode = 500;
}
next(err);
}
};