POST data with user details in mongo db using node.js - node.js

I am developing a web application using the MEAN stack with Angular 6. I have a form to submit data into MongoDB. Following is the save function and it works.
It saves the extruded value in the DB.
saveExtrudedHeightValue(extrudedHeight: NgForm) {
if (extrudedHeight.value != "" && extrudedHeight.value != null) {
this.extrudedHeightService.saveExtrudedHeight(extrudedHeight.value).subscribe(res => {
console.log(res);
}, (err) => {
console.log(err);
});
}
}
Here is the model
// Schema for extruded height panel
var extrudedHeightSchema = new mongoose.Schema({
userName: {
type: String
},
extrudedHeight: {
type: Number
},
});
module.exports = mongoose.model('extrudedHeightValue', extrudedHeightSchema);
Here is my post route
//post extrudedHeight values
router.post("/save", function(req, res) {
var mod = new extrudedHeight(req.body);
extrudedHeight.findOneAndUpdate({
userName: req.body.email,
extrudedHeight: req.body.extrudedHeight,
},
req.body, {
upsert: true,
new: true
},
function(err, data) {
if (err) {
console.log(err);
res.send(err);
} else {
res.send(mod);
}
}
);
});
Here is the service.
// service for save extruded height
saveExtrudedHeight(extrudedHeight): Observable < any > {
return this.http.post('/extrudedHeight/save', extrudedHeight, httpOptions)
.pipe(
catchError(this.handleError)
);
}
Now I want to save data in DB with the current user's userName. I can retrieve the current user's userName by this.
this.payload.user['email']
My problem is that I do not have an idea how to pass this userName to post route to save in db.
Here is where I get token.
this.authService.onTokenChange().subscribe(
(token: NbAuthJWTToken) => {
if (token.isValid()) {
this.user = token.getPayload().user;
this.payload = token.getPayload();
console.log(this.payload.user['email']);
}
}
)

You can first call this.authService.onTokenChange inside the saveExtrudedHeight method, and then use the flatMap operator to unwrap the internal Observable that would be returned by the http.post.
That would translate to code like this:
import { flatMap } from 'rxjs/operators';
import { throwError } from 'rxjs';
...
saveExtrudedHeight(extrudedHeight): Observable<any> {
const requestPayload = {
extrudedHeight
};
return this.authService.onTokenChange()
.pipe(flatMap(
(token: NbAuthJWTToken) => {
if (token.isValid()) {
this.user = token.getPayload().user;
this.payload = token.getPayload();
const email = this.payload.user['email'];
requestPayload.email = email;
// Make the changes here to send the email as the Request Payload.
return this.http.post('/extrudedHeight/save', requestPayload, httpOptions)
.pipe(
catchError(this.handleError)
);
} else {
throwError('Something went wrong!');
}
}
));
}
PS: I'm not really sure if this would work though as I haven't tested it out and I can't without a minimal working StackBlitz.

Related

I'm trying to run this code but it is still sending me the error can't not set headers after they are already send to the client here is my code

router.post("/check", async (req, res) => {
const nom = req.body.nom
const postnom = req.body.postnom
const matricule = req.body.matricule
const numeroBordero = req.body.numero_bordero
const paymentOrder = req.body.payementOrder
const etudiant = Etudiant.findOne({ matricule }, function (err, result) {
if (result == null) {
req.flash("test", "veuillez entrer des infos correctes")
res.redirect("/");
} else if (result !== null) {
if (result.isRegistered !== true) {
Etudiant.updateOne({
_id: result._id
}, {
isRegistered: true
}, function (err) {
if (err) {
console.log(err);
} else {
console.log("correctly updated");
}
})
}
}
})
return res.render("profil", {
etudiant
});
})
Once you call redirect, you cannot call render.
Return after your redirect.
res.redirect("/");
return
What front end framework are you using and what are you trying to accomplish with this endpoint? It seems like the function is checking the value of the request for a record, the running an update if a record was found.
If you want the render on the ui to be conditional on the result of this api call, you need to render separate html accordingly.
I am used to using react or angular, where I simply send a json object to the UI, and let the ui determine which page to navigate to, or which component to conditionally render.
use return res.redirect("/"); instead
You want use async/await but only async is present in your code.
Next, use result === null instead of result == null.
I didn't test your code, but can you run this code ? I think it'll solve your issue.
This code use promises.
router.post("/check", (req, res) => {
const nom = req.body.nom
const postnom = req.body.postnom
const matricule = req.body.matricule
const numeroBordero = req.body.numero_bordero
const paymentOrder = req.body.payementOrder
Etudiant.findOne({ matricule }, function (err, result) {
if (result === null) {
req.flash("test", "veuillez entrer des infos correctes")
res.redirect("/");
} else if (result !== null) {
if (result.isRegistered !== true) {
Etudiant
.updateOne(
{_id: result._id},
{ isRegistered: true}
)
.then(() => {
console.log("correctly updated")
})
.catch((err) => {
console.log(err)
})
}
})
})

I get undefined value when I make a request to the MongoDB database using the mongodb engine in Nodejs

I am using ExpressJS and MongoDB to create a blog for myself. I have created a mini library with the mongodb module to request the MongoDB database.
Here is the library:
'use strict'
const { MongoClient, ObjectId } = require('mongodb')
const { config } = require('../config')
const USER = encodeURIComponent(config.mongodb.user)
const PASS = encodeURIComponent(config.mongodb.pass)
const NAME = config.mongodb.name
const HOST = config.mongodb.host
const URL = `mongodb+srv://${USER}:${PASS}#${HOST}/${NAME}?retryWrites=true&w=majority`
const OPTIONS = {
useNewUrlParser: true,
useUnifiedTopology: true
}
class MongoLib {
constructor () {
this.client = new MongoClient(URL, OPTIONS)
this.name = NAME
}
connect () {
if (!MongoLib.connection) {
MongoLib.connection = new Promise((resolve, reject) => {
this.client.connect(err => {
if (err) reject(err)
console.log('Connected successfully to MongoDB.')
resolve(this.client.db(this.name))
})
})
}
return MongoLib.connection
}
getAll (collection, query) {
return this.connect().then(db => {
return db.collection(collection).find({ query }).toArray()
})
}
get (collection, id) {
return this.connect().then(db => {
return db.collection(collection).findOne({ _id: ObjectId(id) })
})
}
create (collection, data) {
return this.connect().then(db => {
return db.collection(collection).insertOne(data)
}).then(result => result.insertedId)
}
update (collection, id, data) {
return this.connect().then(db => {
return db.collection(collection).updateOne({ _id: ObjectId(id) }, { $set: data }, { upsert: true })
}).then(result => result.upsertedId || id)
}
delete (collection, id) {
return this.connect().then(db => {
return db.collection(collection).deleteOne({ _id: ObjectId(id) })
}).then(() => id)
}
}
module.exports = MongoLib
The database is connecting correctly because I have a seed that injects data into the database using the create method of the library that you just saw.
In the service layer, I create a class with a method called getUser, which will call the getAll method of the MongoDB library, to which we pass a query so that it looks for the user.
'use strict'
const MongoLib = require('../lib/mongo')
const bcrypt = require('bcrypt')
class UsersService {
constructor () {
this.collection = 'users'
this.mongoDB = new MongoLib()
}
async getUser ({ email }) {
// { email } is getted by basic authentication as a "username" to login
// I am receiving this data perfectly
const [user] = await this.mongoDB.getAll(this.collection, { email })
// But the problem start here, the value of user is undefined
return user
}
async createUser ({ user }) {
const { name, email, password } = user
const hashedPassword = await bcrypt.hash(password, 10)
const createUserId = await this.mongoDB.create(this.collection, {
name,
email,
password: hashedPassword
})
return createUserId
}
}
module.exports = UsersService
The problem here is that the user value is undefined. I don't understand why it causes conflict. I'm using async-await to wait for the database request to finish, and the data is in the database correctly.
Does anyone have an idea about this error? If more information needs it, please let me know.
Suspect your query is wrong, you are sending { { email: email } } to mongodb
getAll (collection, query) {
return this.connect().then(db => {
return db.collection(collection).find(query).toArray()
})
}

Can I perform mongoose update from post save middleware?

Is it possible to update a document from a post save mongoose middleware? Because it is not working for me.
I have tried in different ways.
Way 1:
QuoteSchema.post('save', function(doc) {
if (doc.quoteString) {
return;
}
this.quoteString = doc.quoteNumber + "";
this._doc.quoteString = doc.quoteNumber + "";
// update the record with quoteString
this.update({ _id: this.id }, this, { new: true }, function(err, result) {
if (!err) {
console.log("Document Updated");
}
});
console.log('post save', doc.quoteString);
});
Way 2: because this contains the saved object id so I tried directly.
QuoteSchema.post('save', function(doc) {
if (doc.quoteString) {
return;
}
this.quoteString = doc.quoteNumber + "";
this._doc.quoteString = doc.quoteNumber + "";
enter code here
// update the record with quoteString
this.update(function(err) {
if (!err) {
console.log("Document Updated");
}
});
console.log('post save', doc.quoteString);
});
Way 3:
QuoteSchema.post('save', function(doc) {
if (doc.quoteString) {
return;
}
var _quoteString = doc.quoteNumber+"";
this.update({ _id: doc._id }, { $set: { "quoteString": _quoteString } }, function(err) {
if (!err) {
console.log("Document Updated");
}
});
console.log('post save', doc.quoteString);
});
None of these ways works for me.
All I have to do is to update QuoteNumber field after the save. QuoteNumber is being generated from mongoose autoincrement which requires a number field. and I'm also saving a string version of quoteNumber in quoteString field so that in the UI, I can perform regex search in an autocomplete. As regular expression does not work with number type.
any suggestions will be helpful. Thanks.
Just make the autoincrementing field virtual and you don't have to worry about post save hook...
const QuoteSchema = new Schema(
{
quoteNumber: { type: Number },
quoteString: { type: String },
},
);
QuoteSchema.virtual('quote').set(function(value) {
this.quoteNumber = Number(value);
this.quoteString = String(value);
});
QuoteSchema.virtual('quote').get(function() {
return this.quoteNumber;
});
Setup:
QuoteSchema.plugin(autoIncrement.plugin, { model: 'Quote', field: 'quote' });

DELETE request in redux

I'm writing a React Redux CRUD App with Node.js API. I'm struggling with DELETE part.
I'm receiving the successful delete message but nothing has changed in my database. Successful Message in Console
I just wonder why it's not deleting any data?
user.reducer :
import { userConstants } from '../_constants';
export function users(state = {}, action) {
switch (action.type) {
case userConstants.GETALL_REQUEST:
return {
loading: true
};
case userConstants.GETALL_SUCCESS:
return {
items: action.users
};
case userConstants.GETALL_FAILURE:
return {
error: action.error
};
case userConstants.DELETE_REQUEST:
// add 'deleting:true' property to user being deleted
return {
...state,
items: state.items.map(user =>
user.id === action.id
? { ...user, deleting: true }
: user
)
};
case userConstants.DELETE_SUCCESS:
// remove deleted user from state
return {
items: state.items.filter(user => user.id !== action.id)
};
case userConstants.DELETE_FAILURE:
// remove 'deleting:true' property and add 'deleteError:[error]' property to user
return {
...state,
items: state.items.map(user => {
if (user.id === action.id) {
// make copy of user without 'deleting:true' property
const { deleting, ...userCopy } = user;
// return copy of user with 'deleteError:[error]' property
return { ...userCopy, deleteError: action.error };
}
return user;
})
};
default:
return state
}
}
user_actions:
export const userService =
{
delete: _delete,
};
function _delete(id) {
const requestOptions = {
method: 'DELETE',
// headers: authHeader(),
};
return fetch(`/removeadmin/${id}` , requestOptions).then(handleResponse);
}
AdminListPage component :
delete(){
this.props.dispatch(userActions.delete(this.state.delete_user._id));
}
Also, in server-side I'm receiving a successful delete status
ServerSide Console(200)
Server_Side router:
app.delete('/removeadmin/:id', function(req, res)
{
var sent_url = url.parse(req.url, true),
qdata = sent_url.query,
sent_id = qdata.id;
console.log('id ' + sent_id);
admin.removeadmin(sent_id, function(err, user) {
if (err)
throw err;
});
Server_Side delete function:
module.exports.removeadmin = function(id, callback){
var query = { _id: id };
Admin.remove(query, callback);
};
I have deleted a user by simple fetch command in the component without redux and I have sent id in the body of delete request and it was working but with redux just successful message.
Thank you for any help
Your code in the post should work except for the fetch request the url should be prepended with the backend url so if the backend url is localhost:3000 your fetch should be:
return fetch(`http://localhost:3000/removeadmin/${id}`,
requestOptions).then(handleResponse);
and in your serverside router you can access your id param like so:
app.delete('/removeadmin/:id', function(req, res)
{
var send_id = req.params.id;
admin.removeadmin(sent_id, function(err, user) {
if (err)
throw err;
});
I have found that I made a mistake in URL. So on the server in URL I can't have access to my id and it showed me undefined.
Just I have changed these lines :
user_action:
return fetch(`/removeadmin?id=${id}` , requestOptions).then(handleResponse);
and server_side router:
app.delete('/removeadmin?:id', function(req, res){

Push to second level array in mongodb with node/express

I am working on a chatroom where users can chat with each other filtered on the basis on projects. Users from the same project can talk to each other.
Here is my chat model where each document is based on project ref and has an array for the messages with user refference:
'use strict';
var mongoose = require('bluebird').promisifyAll(require('mongoose'));
var ChatSchema = new mongoose.Schema({
projectid: {
type: mongoose.Schema.Types.ObjectId,
ref: 'Project'
},
messages: [{
userid: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
},
message: String,
date: {
type: Date,
default: Date.now
},
time: String
}]
});
export default mongoose.model('Chat', ChatSchema);
Now I am trying to update the messages array with new messages but I am unable to do so since past few hours. Here is what I have so far.
To get chat messages based on projects I am using:
routes:
router.get('/projectid/:id', controller.showByProject);
router.post('/projectid/:id', controller.insertMessageByProject);
controller:
// Gets the chat thread based on project id
export function showByProject(req, res) {
Chat.findAsync({projectid: req.params.id})
.then(handleEntityNotFound(res))
.then(respondWithResult(res))
.catch(handleError(res));
}
// Insert a new message in the chat based on projectid
export function insertMessageByProject(req, res) {
if (req.body._id) {
delete req.body._id;
}
Chat.findAsync({projectid: req.params.id})
.then(handleEntityNotFound(res))
.then(saveUpdates({$push: {messages: req.body}}))
.then(respondWithResult(res))
.catch(handleError(res));
}
Json Object I am sending from POSTMAN:
{
"messages":
{
"userid": "56d7967745ab81322a964927",
"message": "This is a meesage"
}
}
OR
{
"userid": "56d7967745ab81322a964927",
"message": "This is a meesage"
}
I am able to update the object if I have the object ID to the chat document itself but inside my application, I do not have the direct reference. I have tried few other ways as well but every time my application returns a 500 error.
Your help would be highly appreciated.
EDIT 1: here are the helping functions I am using generated by the angular full-stack plugin.
function respondWithResult(res, statusCode) {
statusCode = statusCode || 200;
return function(entity) {
if (entity) {
res.status(statusCode).json(entity);
}
};
}
function saveUpdates(updates) {
return function(entity) {
var updated = _.merge(entity, updates);
return updated.saveAsync()
.spread(updated => {
return updated;
});
};
}
function removeEntity(res) {
return function(entity) {
if (entity) {
return entity.removeAsync()
.then(() => {
res.status(204).end();
});
}
};
}
function handleEntityNotFound(res) {
return function(entity) {
if (!entity) {
res.status(404).end();
return null;
}
return entity;
};
}
function handleError(res, statusCode) {
statusCode = statusCode || 500;
return function(err) {
res.status(statusCode).send(err);
};
}
EDIT 2: As I mentioned in the comments, the problem was with _.Merge function which was not merging the object right, although it should have been able to update the object.
So I wrote my own function for saveUpdates as follows:
function saveUpdatesForNewChat(updates) {
return function(entity) {
var temp = entity;
temp[0].messages.push(updates);
console.log('\ntemp:');
console.log(require('util').inspect(temp, { depth: null }));
console.log('\nend of ops\n\n');
var updated = _.merge(entity, temp);
console.log('out of merge');
console.log(require('util').inspect(updated, { depth: null }));
return updated.saveAsync()
.spread(updated => {
return updated;
});
};
}
ok so I have left the console logs inside and it's perfect object to save into the database but the server still returns a 500 errors on update.
OK! So I have found the answer myself.
The problem was that the object returned was a result set and I was calling save on whole result set. I fetched the first element out of the returned resultset, pushed new message to the element and called save on it and it started working.
Here is the code:
function saveUpdatesForNewChat(updates) {
return function(entity) {
var temp = entity[0];
temp.messages.push(updates);
var updated = temp;
return updated.saveAsync()
.spread(updated => {
return updated;
});
};
}

Resources