Express js - how to remove certain field from response - mysql

In my current login api, it returns
"user": {
"id": "3e85decc-2af4-436c-8b7f-e276771234f5",
"email": "cccc#cccc.com",
"password": "$xxxxxxxxxx",
"createdAt": "2021-05-14T08:48:31.000Z",
"updatedAt": "2021-05-14T08:48:31.000Z"
},
"token": "xxxxx"
}
I want to remove the password field in my response, so I use delete user.password in my code, but it's not working
/api/users.js
router.post('/login', (req, res, next) => {
passport.authenticate('local', {session: false}, (err, user, info) =>{
if (err || !user) {...}
req.login(user, {session: false}, (err) => {
if (err) {
res.send(err);
}
const token = jwt.sign(user, 'your_jwt_secret');
console.log(user) // show dataValues and _previousDataValues instead of normal JSON object
delete user.password // not working
return res.json({user, token});
});
})(req, res);
});
I tried to log user object for above file, it returns:
users {
dataValues: {
id: '3e85decc-2af4-436c-8b7f-e276771234f5',
email: 'cccc#cccc.com',
password: '$xxxxxxxxxx',
createdAt: 2021-05-14T08:48:31.000Z,
updatedAt: 2021-05-14T08:48:31.000Z
},
_previousDataValues: {
id: '3e85decc-2af4-436c-8b7f-e276771234f5',
email: 'cccc#cccc.com',
password: '$xxxxxxxxxx',
createdAt: 2021-05-14T08:48:31.000Z,
updatedAt: 2021-05-14T08:48:31.000Z
},
_changed: Set(0) {},
_options: {
isNewRecord: false,
_schema: null,
_schemaDelimiter: '',
raw: true,
attributes: [ 'id', 'email', 'password', 'createdAt', 'updatedAt' ]
},
isNewRecord: false
}
This is my user model. I am using Sequelize.
const Sequelize = require('sequelize');
const DataTypes = Sequelize.DataTypes;
const db = require('../sequelize')
let users = db.define('users', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
allowNull: false,
primaryKey: true
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: 'email'
},
password: {
type: DataTypes.STRING,
},
},
{
hooks: {
beforeCount(options) {
options.raw = false;
}
}
}
);
module.exports = users;

Finally solved it using user.get({plain: true})
let plainUser = user.get({plain: true})
delete plainUser['password']
return res.json({user, token});

It's probably not a good idea to delete properties from the Model directly. Try using ToJSON() to convert the Model to a plain Javascript object and delete the password from that.
plainUser = user.ToJSON();
delete plainUser.password

why dont you re-create your result response, something like this:
let response = {
"user": {
"id": user.dataValues.id,
"email": user.dataValues.email,
"createdAt": user.dataValues.createdAt,
"updatedAt": user.dataValues.updatedAt
},
"token": "xxxxx"
}
JSON.stringify(response)

Try below code in your model to override the sequelize toJSON function
const User = db.define('users', {
id: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
allowNull: false,
primaryKey: true
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: 'email'
},
password: {
type: DataTypes.STRING,
},
},
{
hooks: {
beforeCount(options) {
options.raw = false;
}
}
}
);
User.prototype.toJSON = function () {
const values = Object.assign({}, this.get());
delete values.password;
return values;
};
or using omit() withlodash for cleaner code
User.prototype.toJSON = function () {
const values = {
..._.omit(this.get(), ['password'])
};
return values;
};

Related

Graphql using Sequelize + mysql: Database Variable always empty

I have gone through many different solutions to overcome this problem. But nothing seems to be working.
My Files:
database.js
const {Sequelize} = require("sequelize");
var db = {}
const sequelize = new Sequelize('ETconnect', 'root', 'D5kIzmJB', {
host: '10.10.10.11',
port: '3306',
dialect: 'mysql',
define: {
freezeTableName: true,
},
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000,
},
// <http://docs.sequelizejs.com/manual/tutorial/querying.html#operators>
operatorsAliases: false,
})
let models = [
require('./models/users.js'),
]
// Initialize models
models.forEach(model => {
const seqModel = model(sequelize, Sequelize)
db[seqModel.name] = seqModel
})
// Apply associations
Object.keys(db).forEach(key => {
if ('associate' in db[key]) {
db[key].associate(db)
}
})
db.sequelize = sequelize
db.Sequelize = Sequelize
exports.db;
models/users.js
const {Sequelize} = require('sequelize');
module.exports = function(sequelize, DataTypes) {
return sequelize.define('users', {
id: {
autoIncrement: true,
type: DataTypes.INTEGER.UNSIGNED,
allowNull: false,
primaryKey: true
},
name: {
type: DataTypes.STRING(50),
allowNull: false
},
email: {
type: DataTypes.STRING(50),
allowNull: false,
unique: "email"
},
password: {
type: DataTypes.STRING(255),
allowNull: false
},
profileimage: {
type: DataTypes.STRING(45),
allowNull: true
}
}, {
sequelize,
tableName: 'users',
timestamps: false,
indexes: [
{
name: "PRIMARY",
unique: true,
using: "BTREE",
fields: [
{ name: "id" },
]
},
{
name: "email",
unique: true,
using: "BTREE",
fields: [
{ name: "email" },
]
},
]
});
};
models/init-models.js
var DataTypes = require("sequelize").DataTypes;
var _users = require("./users");
function initModels(sequelize) {
var users = _users(sequelize, DataTypes);
return {
users,
};
}
module.exports = initModels;
module.exports.initModels = initModels;
module.exports.default = initModels;
Graphql/users.js
const {gql} = require("apollo-server-express");
const db = require("../database");
//import { gql } from 'apollo-server-express'
//import * as db from '../database'
exports.typeDefs = gql`
extend type Query {
users: [User]
user(id: ID!): User
}
type User {
id: ID!
name: String
email: String
}
`
exports.resolvers = {
Query: {
users: async () => console.log(db),
user: async (obj, args, context, info) =>
db.users.findByPk(args.id),
},
}
Everytime I use the users query in the Apollo test environment I get a log which says that the Database variable is empty.
Output: {}
Can anybody tell me what I did wrong? Does it not connect to the Database? Because we have a similar application that does perfectly fine.
I would really appreciate the help.

TypeError: models.leaves.getAllEmpoyees is not a function

I am writing a function in Schema Model for getting Data with a query. The query is working fine, but unfortunately i am getting an error regarding Function - getAllEmpoyees() not found. For Reference - my sequelize version is - 6.15.0 . I am new to Node.js. Can anyone help me out yrr, Thanks in Advance!
const Sequelize = require('sequelize');
module.exports = function(sequelize, DataTypes) {
return sequelize.define('leaves', {
id: {
autoIncrement: true,
type: DataTypes.BIGINT.UNSIGNED,
allowNull: false,
primaryKey: true
},
employee_id: {
type: DataTypes.INTEGER,
allowNull: false
},
leave_type_id: {
type: DataTypes.INTEGER,
allowNull: false
},
leave_reason: {
type: DataTypes.STRING(255),
allowNull: false
},
remark: {
type: DataTypes.STRING(255),
},
status: {
type: DataTypes.STRING(255),
allowNull: false
},
created_by: {
type: DataTypes.INTEGER
}
},
{
sequelize,
tableName: 'leaves',
timestamps: true,
indexes: [
{
name: "PRIMARY",
unique: true,
using: "BTREE",
fields: [
{ name: "id" },
]
},
]
},
getAllEmpoyees = function() {
var query = "select * from leaves as l join leave_types as lt on l.leave_type_id=lt.id";
return sequelize.query(query, { type: sequelize.QueryTypes.SELECT});
},
);
};
const express = require('express');
const router = express.Router();
var path = require('path');
var root_path = path.dirname(require.main.filename);
var models = require(root_path + '/models');
var moment = require("moment");
router.get('/getallemployeeLeaves', (req, res) => {
console.log("All Fetched");
models.leaves.getAllEmpoyees().then(function (data) {
console.log("");
if (data.length > 0) {
res.json({
status: 200,
data: data
})
} else {
res.json({
status: 400,
})
}
})
})

Sequelize - is it possible to limit the number of record in junction table

There are 3 tables student_teacher, student, teacher with below relationship.
Each teacher will be responsible for 5 students, so the relationship should be 1 to Many, but I decide to create a junction table for storing extra information for this relationship.
When I create a student_teacher record, the payload will be like this:
{
"studentId": "xxx",
"teacherId": "yyy",
"groupName": "Group A"
}
Let's say I have record below now in table student_teacher:
[
{
"studentId": "studentA",
"teacherId": "teacherA",
"groupName": "Group X"
},
{
"studentId": "studentB",
"teacherId": "teacherA",
"groupName": "Group X"
},
{
"studentId": "studentC",
"teacherId": "teacherA",
"groupName": "Group X"
},
{
"studentId": "studentD",
"teacherId": "teacherA",
"groupName": "Group X"
},
{
"studentId": "studentE",
"teacherId": "teacherA",
"groupName": "Group X"
}
]
There are already 5 record for teacherA in table student_teacher, I will to forbid to create 1 more record for teacherA.
Is it possible to do it in Sequelize? Or handle I need to handle it in node.js function?
student-teacher.model.js
const Sequelize = require('sequelize');
const DataTypes = Sequelize.DataTypes;
module.exports = function (app) {
const sequelizeClient = app.get('sequelizeClient');
const studentTeacher = sequelizeClient.define('student_teacher', {
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
defaultValue: Sequelize.UUIDV4,
},
studentId: {
allowNull: false,
type: DataTypes.UUID,
references: { model: 'student', key: 'id' },
defaultValue: Sequelize.UUIDV4,
unique: 'studentId_foreign_idx'
},
teacherId: {
allowNull: false,
type: DataTypes.UUID,
references: { model: 'teacher', key: 'id' },
defaultValue: Sequelize.UUIDV4,
unique: 'teacherId_foreign_idx'
},
groupName: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: ''
},
...
}, {
hooks: {
beforeCount(options) {
options.raw = true;
}
}
});
studentTeacher.associate = function (models) {};
return studentTeacher;
};
student.model.js
const Sequelize = require('sequelize');
const DataTypes = Sequelize.DataTypes;
module.exports = function (app) {
const sequelizeClient = app.get('sequelizeClient');
const student = sequelizeClient.define('student', {
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
defaultValue: Sequelize.UUIDV4,
},
email: {
type: DataTypes.STRING,
allowNull: false,
isEmail: true,
unique: 'email'
},
firstName:{
type: DataTypes.STRING,
allowNull: false,
defaultValue: '',
},
lastName:{
type: DataTypes.STRING,
allowNull: false,
defaultValue: '',
}
}, {
hooks: {
beforeCount(options) {
options.raw = true;
}
}
});
student.associate = function (models) {
student.belongsToMany(models.teacher, { as: 'teachers', through: 'student_teacher', foreignKey: 'studentId', onDelete: 'cascade' })
};
return student;
};
teacher.model.js
const Sequelize = require('sequelize');
const DataTypes = Sequelize.DataTypes;
module.exports = function (app) {
const sequelizeClient = app.get('sequelizeClient');
const teacher = sequelizeClient.define('teacher', {
id: {
allowNull: false,
primaryKey: true,
type: DataTypes.UUID,
defaultValue: Sequelize.UUIDV4,
},
email: {
type: DataTypes.STRING,
allowNull: false,
}
}, {
hooks: {
beforeCount(options) {
options.raw = true;
}
}
});
teacher.associate = function (models) {
teacher.belongsToMany(models.student, { as: 'students', through: 'student_teacher', foreignKey: 'teacherId', onDelete: 'cascade' })
};
return teacher;
};
Sequelize's hooks are very compatible with your requirement:
// in your student-teacher.model.js model (before you return the model)
studentTeacher.beforeCreate(async (instance, options) => {
try {
const result = await studentTeacher.findAll({
where: {
teacherId: instance.teacherId
}
});
if(result.length === MAX_RECORDS_FOR_TEACHER) {
throw new Error(`Cannot create more instnaces for ${instance.teacherId}`);
}
}
catch(e) {
throw e; // You must throw an error inside the hook in order to cancel
// the real statement execution.
}
});
Read more: https://sequelize.org/master/manual/hooks.html

Unable to insert id into a table that belongs to a foreign key referenced table using Sequelize

I am building serverless application using node js and using claudia-api-builder as a framework to launch APIs in AWS.
In app.js file, i call the required api as
const ApiBuilder = require('claudia-api-builder');
const api = new ApiBuilder();
module.exports = api;
api.post('/api/auth/validatephonenumber', async function (request)
{
return new Promise((resolve, reject) => {
index.loadDatabase().then((db) => {
resolve(loginController.validatePhonenumber(db, request));
});
});
});
Below is my code:
async function validatePhonenumber(db, request) {
return new Promise(
async (resolve, reject) => {
let emailid;
await db.EmailRegistration.sync().then(function () {
emailid = db.EmailRegistration.findOne({
where: { email: { [Op.eq]: mailid } },
attributes: ['id'],
});
});
if (emailid != null) {
console.log(`email id: ${emailid.id}`);
await db.ContactDetails.sync().then(function () {
db.ContactDetails.findOrCreate({
where: { contactnumber: phnum },
defaults: { EmailRegistrationId: emailid.id },
}).spread((contactdetails, created) => {
console.log(`contactdetails: ${contactdetails}`);
if (contactdetails !== null) {
resolve({ statuscode: indexController.statusCode.statusOK, contactdetails: contactdetails })
} else {
reject({ statuscode: indexController.statusCode.InternalServerError, message: 'phone number not created' });
}
});
});
};
});
}
I am trying to add a emailregistrationid of EmailRegistration table into ContactDetails table as a foreign key reference. I am using sequelize with mysql, nodejs to achieve the desired results. But, i am getting below error:
Unhandled rejection SequelizeForeignKeyConstraintError: Cannot add or update a child row: a foreign key constraint fails (inmeeydb.ContactDetails, CONSTRAINT ContactDetails_ibfk_1 FOREIGN KEY (EmailRegistrationId) REFERENCES EmailRegistration (id) ON DELETE CASCADE ON UPDATE CASCADE)
Below is my EmailRegistration models file:
const moment = require('moment');
module.exports = (sequelize, DataTypes) => {
const EmailRegistration = sequelize.define(
'EmailRegistration',
{
id: {
type: DataTypes.UUID,
primaryKey: true,
allowNull: false,
defaultValue: DataTypes.UUIDV4,
},
email: {
type: DataTypes.STRING(50),
allowNull: false,
},
password: {
type: DataTypes.STRING,
allowNull: false,
validate: { min: 6 },
},
createdAt: {
type: DataTypes.DATE,
get() {
return moment.utc(new Date(), 'DD/MM/YYYY h:mm a').format('DD/MM/YYYY h:mm a');
},
},
updatedAt: {
type: DataTypes.DATE,
defaultValue: null,
},
},
{
freezeTableName: true,
}
);
EmailRegistration.associate = function (models) {
EmailRegistration.hasOne(models.ContactDetails,
{ foreignKey: 'EmailRegistrationId' }
);
};
return EmailRegistration;
};
Below is my Contactdetails models file:
const moment = require('moment');
module.exports = (sequelize, DataTypes) => {
const ContactDetails = sequelize.define(
'ContactDetails',
{
id: {
type: DataTypes.UUID,
primaryKey: true,
allowNull: false,
defaultValue: DataTypes.UUIDV4,
},
contactnumber: { type: DataTypes.STRING(13), allowNull: false },
isverified: { type: DataTypes.BOOLEAN, defaultValue: false },
createdAt: {
type: DataTypes.DATE,
get() {
return moment.utc(new Date(), 'DD/MM/YYYY h:mm a').format('DD/MM/YYYY h:mm a');
},
},
updatedAt: {
type: DataTypes.DATE,
defaultValue: null,
},
},
{
indexes: [{ fields: ['contactnumber'], unique: true }],
},
{
freezeTableName: true,
}
);
ContactDetails.associate = function(models) {
ContactDetails.belongsTo(models.EmailRegistration, {
onDelete: 'CASCADE',
hooks: true,
foreignKey: { allowNull: false },
});
};
return ContactDetails;
};
I tried to change the code as below with reference in both tables, but nothing worked.
ContactDetails.associate = function(models) {
ContactDetails.belongsTo(models.EmailRegistration,
{ foreignKey: 'EmailRegistrationId' }
);
};
Not able to analyze how to overcome the issue. This worked fine when i used nodejs with expressjs and had no issues. It fails to identify the EmailRegistrationId(that is missing in the query) in ContactDetails table and shows the output as
INSERT INTO `ContactDetails` (`id`,`contactnumber`,`isverified`,`createdAt`,`updatedAt`) VALUES ('52974e07-8489-4101-ab71-6af874903290','+xxxxxxxxx',false,'2018-10-12 08:55:35','2018-10-12 08:55:35');
You need to update the configuration of your association. The ContactDetails model will now have a field called emailregistrationid
EmailRegistration.associate = function (models) {
EmailRegistration.hasMany(models.ContactDetails);
};
ContactDetails.associate = function(models) {
ContactDetails.belongsTo(models.EmailRegistration, {
onDelete: 'CASCADE',
hooks: true,
foreignKey: {
name: 'emailregistrationid'
allowNull: false
},
});
}
ContactDetails.create({
...
emailregistrationid: <some_valid_emailregistrationid>
})

TypeError: Cannot read property 'findOne' of undefined while using sequelize in node

I am getting belo mentioned error when trying to make user authentication using passport-local and sequelize for MySQL. When running server it is creating new table in SQL if not already, but as soon as I hit sign up button it is showing error.
Error:
TypeError: Cannot read property 'findOne' of undefined
at Strategy._verify (E:\Web Development\node-SQL-Sequelize-passport-local\config\passport\passport.js:19:13)
at Strategy.authenticate (E:\Web Development\node-SQL-Sequelize-passport-local\node_modules\passport-local\lib\strategy.js:88:12)
at attempt (E:\Web Development\node-SQL-Sequelize-passport-local\node_modules\passport\lib\middleware\authenticate.js:361:16)
at authenticate (E:\Web Development\node-SQL-Sequelize-passport-local\node_modules\passport\lib\middleware\authenticate.js:362:7)
My server.js look like :
app.use(passport.initialize());
app.use(passport.session());
//Models
var models = require("./app/models");
//Routes
var authRoute = require('./app/routes/auth.js')(app,passport);
require('./config/passport/passport.js')(passport, models.user);
//Sync Database
models.sequelize.sync().then(function() {
console.log('Nice! Database looks fine')
}).catch(function(err) {
console.log(err, "Something went wrong with the Database Update!")
});
app.get('/', function(req, res) {
res.send('Welcome to Passport with Sequelize');
});
My user.js file:
module.exports = function(sequelize, Sequelize) {
var User = sequelize.define('userInfo', {
id: {
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
firstname: {
type: Sequelize.STRING,
notEmpty: true
},
lastname: {
type: Sequelize.STRING,
notEmpty: true
},
username: {
type: Sequelize.TEXT
},
about: {
type: Sequelize.TEXT
},
email: {
type: Sequelize.STRING,
validate: {
isEmail: true
}
},
password: {
type: Sequelize.STRING,
allowNull: false
},
last_login: {
type: Sequelize.DATE
},
status: {
type: Sequelize.ENUM('active', 'inactive'),
defaultValue: 'active'
}
});
return User;
}
My passport.js file :
var bCrypt = require('bcrypt-nodejs');
module.exports = function(passport, user) {
var User = user;
var LocalStrategy = require('passport-local').Strategy;
passport.use('local-signup', new LocalStrategy(
{
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},function(req, email, password, done) {
var generateHash = function(password) {
return bCrypt.hashSync(password, bCrypt.genSaltSync(8), null);
};
User.findOne({
where: {
email: email
}
}).then(function(user) {
if (user)
{
return done(null, false, {
message: 'That email is already taken'
});
} else
{
var userPassword = generateHash(password);
var data =
{
email: email,
password: userPassword,
firstname: req.body.firstname,
lastname: req.body.lastname
};
User.create(data).then(function(newUser, created) {
if (!newUser) {
return done(null, false);
}
if (newUser) {
return done(null, newUser);
}
});
}
});
}
));
}
Review this example: github.com/sequelize/express-example. In particular models/index.js for models load.
That way is handled in that example is:
require('./config/passport/passport.js')(passport, models.userInfo);
Because "userInfo" is defined in your model user.js: