I'm looking for a way to update multiple documents in a single request but according to ottoman git issues, atomic update is not supported. I have 2 models :
var Profile = ottoman.model('Profile', {
email : 'string',
firstname : 'string,
password : 'string,
Id : 'string'
};
var User = ottoman.model('User', {
creditCard : 'string',
userId : 'string'
};
This is my model
var user = {
update : (req, res) => {
var newEmail = req.body.email.trim();
var newPassword = req.body.email.trim();
User.find({userId : req.params.userId}, (err, user) => {
user.creditCard = 'XXXXXXXXXX';
user.save((err) => {
if(err){
//send error code
}
//logic here
//console.log(logic appears)
Profile.find({ Id : user.userId}, (err, profile) => {
profile.email = newEmail;
//logic here all skipped
profile.save((err) => {
if(err){
//send error
}
console.log(success);
})
});
});
});
}
};
and in my route :
router.post('/update', user.update);
Can anyone give me a clue to deal with updating 2 separates models. I'd be appreciated. thx
Related
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
}],
I tried this code to send a Firebase notification when posting data to my remote DB, using a hardcoded Registration Token, it worked (notification + storage) :
const mongoose = require('mongoose');
const Offer = require('../models/offer');
var admin = require("firebase-admin");
var payload = {
notification: {
title: "This is a Notification",
body: "This is the body of the notification message."
}
};
var options = {
priority: "high",
timeToLive: 60 * 60 *24
};
//exports to my Express.Router.post()
//which is in a different file : router.post('/', OffersController.offers_create_offer);
exports.offers_create_offer = (req, res, next) => {
const offer = new Offer({
_id : new mongoose.Types.ObjectId(),
userId : req.body.userId,
postId : req.body.postId,
pricingDetails : req.body.pricingDetails,
serviceDetails : req.body.serviceDetails
});
offer.save().then(result => {
//my hardcoded Registration Token
admin.messaging().sendToDevice("dfs...f49", payload, options)
.then(function(response) {
console.log("Successfully sent message:", response);
})
.catch(function(error) {
console.log("Error sending message:", error);
});
console.log(result);
res.status(201).json({
message : 'Offer created successfully',
offer : {
_id : result._id,
userId : result.userId,
postId : result.postId,
pricingDetails : result.pricingDetails,
serviceDetails : result.serviceDetails
}
})
})
.catch(err => {
console.log(err);
res.status(500).json({
error : err
});
});
};
and now I want to get the Token from my user schema :
const mongoose = require('mongoose');
const userSchema = mongoose.Schema({
_id : mongoose.Schema.Types.ObjectId,
email : {
type : String,
required : true,
unique : true,
match : /[a-...])?/
},
password : {type : String, required : true},
name : {type : String, required : true},
FCMRegToken : {type : String, required : true},
});
module.exports = mongoose.model('User', userSchema);
Here is my post body just in case :
{
"userId": "5...c4",
"postId": "5...2b",
"pricingDetails" : "pricing",
"serviceDetails" : "details",
"jobUserId" : "5...3f"//which is a different userId
}
I specifically need to get the FCMRegToken that corresponds to req.body.jobUserId like below :
...
const Offer = require('../models/offer');
const User = require('../models/user');
...
exports.offers_create_offer = (req, res, next) => {
//trying to get the Token
user = User.findOne({ _id : req.body.jobUserId});
FCMRegToken = user.FCMRegToken;
...
offer.save().then(result => {
//trying to pass it as an argument
admin.messaging().sendToDevice(FCMRegToken , payload, options)
.then(function(response) {
console.log("Successfully sent message:", response);
})
.catch(function(error) {
console.log("Error sending message:", error);
});
but it didn't work and i get a warning that my FCMRegToken "must be a non-empty String...", knowing that I checked my DB and made sure that the Token where _id = jobUserId is not empty and correct.
Is there a right way to achieve this goal ?
After trying somethings I found a way ... more like I understood how queries work in mongoose, here is what worked for me :
...
const Offer = require('../models/offer');
const User = require('../models/user');
...
exports.offers_create_offer = (req, res, next) => {
...
offer.save().then(result => {
console.log(result);
res.status(201).json({
message : 'Offer created successfully',
offer : {
_id : result._id,
userId : result.userId,
postId : result.postId,
pricingDetails : result.pricingDetails,
serviceDetails : result.serviceDetails
}
})
//trying to get the corresponding user document
const user = User.findOne({ _id : req.body.postUserId});
user.select('_id FCMRegToken')
.exec()
.then(doc => {
//trying to pass the user doc's property FCMRegToken as an argument
admin.messaging().sendToDevice(doc.FCMRegToken , payload, options)
.then(function(response) {
console.log("Successfully sent message:", response);
})
.catch(function(error) {
console.log("Error sending message:", error);
});
})
})
...
I correctly setup mongoose.encryption into my code. I know that because when I go to '/register' route, my password is encrypted properly.
app.get('/cadastrar', (req, res) => {
res.render('registrar');
});
app.post('/cadastrar', (req, res) =>{
const cadastro = req.body.cadastro;
User.create({nickname: cadastro.nickname, email: cadastro.email, password: cadastro.password},(err) => {
err ? console.log(err) : console.log('Successfully added a new user!'); res.render('/');
});
})
Below my password after registering:
{
"_id" : ObjectId("5cbb2dce3014e52b34732df8"),
"nickname" : "Bulbassauro",
"email" : "bulba#pokemon.com",
"_ct" : { "$binary" : "YeLrW1jgdaT4IBFaBExr+Y4IUVkA5UtJoww6hYKqynAVg7OYjEuhJhQt2z2CtIBPHQ==", "$type" : "00" },
"_ac" : { "$binary" : "YUmRsA2QBkUw9fgyNTimqAeEPxsLgjtI4bLErh2FJmZCWyJfaWQiLCJfY3QiXQ==", "$type" : "00" },
"__v" : 0
}
I refactored my code, so I have a different file which I setup my mongoose.Schema:
const mongoose = require('mongoose');
const encrypt = require('mongoose-encryption');
const userSchema = new mongoose.Schema(
{
nickname : String,
email : String,
password : String
}
);
const secret = 'viciadoemjogo';
userSchema.plugin(encrypt, {secret: secret, encryptedFields:['password']});
module.exports = mongoose.model('User', userSchema);
And below is my route to login. But I can not log in. This means that my password is not being decrypted.
That's when I get the error: Authentication code missing
app.get('/login', (req, res) => {
res.render('registrar');
});
app.post('/login', (req, res) => {
const email = req.body.login.email;
const password = req.body.login.password;
User.findOne({email: email}, (err, foundUser) =>{
if(err){
console.log(err);
} else {
if(foundUser){
if(foundUser.password === password){
res.render('nivelamento');
}
}
}
});
});
Can anyone tell me why I can not log in?
The error is from
const email = req.body.login.email;
const password = req.body.login.password;
it should be
const email = req.body.email;
const password = req.body.password;
Once you update your code to this changes, everything will work. how mongoose encryption works is that, when you save() it encrypts and when you call find() or findOne() it will decrypt. So you are comparing pass-string with pass-string not pass-hash.
I want to write a rest api, with which i am able to download some data. All datas were stored in a mongodb. I don't know what to pass to the download method, to make it possible.
Here is my current code:
router.get('/download/:productId/:username/:token', function (req, res) {
var auth = require('../provider/authProvider.js');
var authInst = new auth();
authInst.checkAuth(req.params.username, req.params.token, res, function (err, obj) {
if (obj == true) {
res.status(200);
// here is my problem, what to pass to the download-method
res.download('');
}
});
});
I could not find anything else, than passing paths to the download method.
Does anyone has an idea how to solve my problem?
I assume you know how to set up mongoose environment, putting config, connecting to MongoDB. If not please refer to my answer here.
Now let's say we have a Document in MongoDB as Blog.
So we need to create a model for Blog so that we can do CRUD operations using Mongoose ORM.
you need mongoose module for this to be included in your project.
so run this command from your project root directory, it will automatically download mongoose for you.
npm install mongoose --save
BlogModel.js
var mongoose = require("mongoose");
var Schema = mongoose.Schema;
var BlogSchema = new Schema({
"title" : { type: String },
"user_id" : { type: String },
"blog_uri" :{ type: String },
"post_date" : { type : Date, default: Date.now},
"body" : { type: String, default: '' },
"comments" : [
{ 'content' : { type: String },
'user_id' : { type: String },
'comment_date' : { type: Date },
'votes' : [
{
'user_id' : { type: String }
}
]
}
],
"hidden" : {type:Boolean, default: false }
});
mongoose.model('Blog', BlogSchema);
So let's create a separate file called BlogController.js where we will write methods for CRUD.
var mongoose = require('mongoose');
var Blog = mongoose.model('Blog');
var ObjectId = require('mongoose').Types.ObjectId;
exports.create = function(req,res){
var blog = new Blog(req.body);
blog.save(function(err){
if(err)
res.json({message: "Error occured while saving"});
else{
res.redirect('/home');
}
});
};
exports.getAll = function(req,res){
Blog.find(function(err,blogs){
if(err){
res.send(err);
}else{
res.json(blogs);
}
});
};
exports.get = function(req,res){
var id ;
try{
id = new ObjectId(req.params.id);
Blog.findById(id,function(err,blog){
if(err){
res.send(err);
}else{
res.render('blog.ejs', {
blog: blog
});
}
});
}catch(e){
res.send(404);
}
};
exports.update = function(req,res){
var id ;
try{
id = new ObjectId(req.params.blog_id);
Blog.findById(id,function(err,blog){
if(err){
res.send(err);
}
blog.save(function(err){
if(err)
res.send(err);
res.render('blog.ejs', {
message: "Blog Updated successfully"
});
});
});
}catch(e){
res.send(404);
}
};
exports.delete = function(req,res){
var id ;
try{
id = new ObjectId(req.params.blog_id);
Blog.remove({_id:id},function(err,blog){
if(err){
res.send(err);
}
res.render('blog.ejs', {
message: "Blog deleted successfully"
});
});
}catch(e){
res.send(404);
}
};
So this was about CRUD using Mongoose. I usually don't use res.render(..) in my projects because i put Templating logic in front end. I just use res.json(..) and pass the json data to the the frontend. So please go ahead and try. I hope i answered your question. You can refer to
this repo, for better example. Here i got a very clean CRUD implementation.
I have written the following method that searches for a user in the database by their email.
/**
* Find a user by providing their email address
*/
DataProvider.prototype.findUserByEmail = function(callback, email) {
console.log("in findUserByEmail");
User.findOne({
emailAddress : email
}, function(error, user) {
if(error) {
console.log(error);
callback(error);
}
else {
console.log(user);
callback(user);
}
});
};
I'm trying to test it with the following:
function testFindUserByEmail() {
var expectedEmail = "user#user.com";
data.findUserByEmail(function(user) {
if (user.emailAddress === expectedEmail) {
console.log("User found");
} else {
console.log("User not found");
}
console.log(user);
}, "user#user.com");
console.log("test");
}
I get an outout of:
in findUserByEmail
test
It's like User.findOne() isn't getting called and I don't know why.
Other info:
var UserSchema = new Schema({
emailAddress : {
type : String
},
occupation : {
type : String
},
token : {
type : String
},
password : {
type : String
},
registrationDate : {
type : Date
},
activated : {
type : Boolean
}
});
/**
* Define Model
*/
var User = mongoose.model('User', UserSchema);
DataProvider = function() {
};
did you connected the database,
try: mongoose.connect('db-uri', function (err) {
next(err);
});