Here is my code:
models/index.js:
var Sequelize = require('sequelize');
// initialize database connection
var sequelize = new Sequelize('somedb', '', '', {
host: 'localhost',
dialect: 'sqlite',
pool:{
max: 5,
min: 0,
idle: 10000
},
storage: "db/main.db"
});
// load models
var models = [
'Users',"Clients"
];
models.forEach(function(model) {
module.exports[model] = sequelize.import(__dirname + '/' + model);
module.exports[model].sync();
});
// export connection
module.exports.sequelize = sequelize;
app.js:
SQLized.sync().then(function(err){
//Settings Environmental Variables
var env = process.env.STAGE;
var config = require("./config.js")[env];
...
});
models/Users.js:
var Sequelize = require("sequelize");
var hash = require("../modules/util/hash");
module.exports=function(sequelize, DataTypes){
return Users = sequelize.define("Users", {
id: {
type: DataTypes.INTEGER,
field: "id",
autoIncrement: !0,
primaryKey: !0
},
firstName: {
type: DataTypes.STRING,
field: "first_name"
},
lastName: {
type: DataTypes.STRING,
field: "last_name"
},
username: {
type: DataTypes.STRING,
field: "username"
},
email: {
type: DataTypes.STRING,
field: "email"
},
password: {
type: DataTypes.STRING,
field: "password"
},
token: {
type: DataTypes.STRING,
field: "access_token"
},
isAdmin: {
type: DataTypes.BOOLEAN,
field: "isAdmin"
}
}, {
freezeTableName: true, // Model tableName will be the same as the model name
classMethods:{
usernameExists: function(username, _clb){
},
userExists: function(username, _clb){
},
signup: function(params, _clb){
var fullnm_splt = params.fullname.split(' ');
params.firstName = (fullnm_splt.length >2) ? fullnm_splt.slice(0, -1).join(" ") : fullnm_splt[0];
params.lastName = (fullnm_splt.length >2) ? fullnm_splt.slice(-1).join(" ") : fullnm_splt[1];
res.redirect("/users/" + params.username);
}
},
instanceMethods:{
isValidPassword: function(password, _clb){
var _self = this;
hash(password, function(err, password_encr){
if(err){
return _clb(err);
}
if(password_encr == _self.password){
return _clb(null, true);
}
return _clb(null, false);
});
}
}
});
};
models/Clients.js
var Sequelize = require("sequelize");
module.exports=function(sequelize, DataTypes){
return Clients = sequelize.define("Clients", {
id:{
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
client_name: {
type: DataTypes.STRING,
field: "client_name"
},
client_host_name: {
type: DataTypes.STRING,
field: "client_host_name"
},
ip: {
type: DataTypes.STRING,
field: "ip"
},
mac: {
type: DataTypes.STRING,
field: "mac"
},
previous_ip: {
type: DataTypes.STRING,
field: "previous_ip"
}
}, {
freezeTableName: true, // Model tableName will be the same as the model name
classMethods:{
},
instanceMethods:{
}
});
};
When I try to save something to DB, with the function below, it states the INSERT INTO query in the logs but nothing changes in the db file.
create_client:
Clients
.create({client_host_name: params.client_host_name, ip: params.ip, mac: params.mac})
.then(function(err){
res.send("OK");
});
How can I solve this?
I've tested your app, everything inserts okay check out https://github.com/finfort/SequelizeTestRepo
Related
this is user model
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
class User extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate({ Kyc }) {
// define association here
this.hasOne(Kyc, { foreignKey: "userID" });
}
}
User.init(
{
uuid: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
allowNull: false,
},
firstname: {
type: DataTypes.STRING,
allowNull: false,
},
lastname: {
type: DataTypes.STRING,
allowNull: false,
},
email: {
type: DataTypes.STRING,
allowNull: false,
},
role: {
type: DataTypes.STRING,
defaultValue: "user",
allowNull: false,
validate: {
roles(value) {
const rolesArray = ["user", "admin"];
if (!rolesArray.includes(value)) {
throw new Error('plese enter valid role "user or admin"');
}
},
},
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
},
{
sequelize,
modelName: "User",
}
);
return User;
};
this is kyc model
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
class Kyc extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate({ User }) {
// define association here
this.belongsTo(User, { foreignKey: "userID", as: "user" });
}
}
Kyc.init(
{
uuid: {
type: DataTypes.UUID,
defaultValue: DataTypes.UUIDV4,
allowNull: false,
},
docimg: {
type: DataTypes.STRING,
allowNull: false,
},
details: {
type: DataTypes.STRING,
allowNull: false,
},
status: {
type: DataTypes.STRING,
allowNull: false,
},
userID: {
type: DataTypes.INTEGER,
allowNull: false,
},
},
{
sequelize,
modelName: "Kyc",
}
);
return Kyc;
};
kyc middlware
const verifyKyc = async (req, res, next) => {
// check that user has posted or not if yes then give error
const user = await User.findByPk(req.user.id);
const kyc = await Kyc.findOne({
userID: req.user.id,
});
console.log(user.id);
console.log(kyc);
if (user.id === kyc) {
}
next();
};
Error
Executing (default): SELECT "id", "uuid", "firstname", "lastname", "email", "role", "password", "createdAt", "updatedAt" FROM "Users" AS "User" WHERE "User"."id" = 1;
(sequelize) Warning: Model attributes (userID) passed into finder method options of model Kyc, but the options.where object is empty. Did you forget to use options.where?
Executing (default): SELECT "id", "uuid", "docimg", "details", "status", "userID", "createdAt", "updatedAt" FROM "Kycs" AS "Kyc" LIMIT 1;
1
Kyc {
dataValues: {
id: 117,
uuid: '99461f78-4781-42cc-a01f-b6541fda849d',
docimg: 'admin.png',
details: 'KSAPK0550P',
status: 'pending',
userID: 1,
createdAt: 2022-06-04T10:59:21.039Z,
updatedAt: 2022-06-04T10:59:21.039Z
_previousDataValues: {
id: 117,
uuid: '99461f78-4781-42cc-a01f-b6541fda849d',
docimg: 'admin.png',
details: 'KSAPK0550P',
status: 'pending',
userID: 1,
createdAt: 2022-06-04T10:59:21.039Z,
updatedAt: 2022-06-04T10:59:21.039Z
isNewRecord: false
}
i am tring to print userID but giving me this error
thank you for your help
You forgot to wrap your condition into where option:
const kyc = await Kyc.findOne({
where: {
userID: req.user.id,
}
});
I'm using Sequelize for my Postgres database. I have a Messages and a Users table; a user has many messages and a message belongs to a user. I've defined my models as follows:
User
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
firstName: {
type: DataTypes.STRING,
allowNull: false
},
lastName: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true,
}
},
password: {
type: DataTypes.STRING,
allowNull: false,
validate: {
len: [8, 50],
}
},
}, {
modelName: 'User',
});
User.associate = (models) => {
User.hasMany(models.Message, { foreignKey: 'userId', as: 'Messages' })
}
return User;
};
Message
module.exports = (sequelize, DataTypes) => {
const Message = sequelize.define('Message', {
content: {
allowNull: false,
type: DataTypes.STRING,
validate: {
len: [1, 248],
}
},
userId: {
type: DataTypes.INTEGER,
allowNull: false,
references: {
model: 'Users',
key: 'id'
}
},
likes: {
defaultValue: 0,
type: DataTypes.INTEGER
},
}, {
modelName: 'Message',
});
Message.associate = (models) => {
Message.belongsTo(models.User, { foreignKey: 'userId', as: 'User', onDelete: 'CASCADE' })
}
return Message;
};
And here's how I'm testing them:
User.create({
firstName: 'Test', lastName: 'Test', email: 'test#test.com', password: '87654321'
}).then((newUser) => {
console.log(newUser.get())
})
Message.bulkCreate([
{ content: "Hello", likes: 0, userId: 1 },
{ content: "Hello World", likes: 0, userId: 1 },
{ content: "Hello World 2", likes: 123, userId: 1 }
])
.then((newMessages) => {
console.log(newMessages)
})
const findAllWithMessages = async () => {
const users = await User.findAll({
include: [{
model: Message
}]
});
console.log(JSON.stringify(users, null));
}
Here's my Migration file to create the users table:
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
firstName: {
type: Sequelize.STRING,
allowNull: false
},
lastName: {
type: Sequelize.STRING,
allowNull: false
},
email: {
type: Sequelize.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true,
}
},
password: {
type: Sequelize.STRING,
allowNull: false,
validate: {
len: [8, 50],
}
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('Users');
}
};
And the messages table:
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Messages', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
userId: {
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'Users',
key: 'id',
as: 'userId',
},
onUpdate: 'CASCADE',
onDelete: 'SET NULL',
},
content: {
allowNull: false,
type: Sequelize.STRING,
validate: {
len: [1, 248],
}
},
likes: {
defaultValue: 0,
type: Sequelize.INTEGER
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('Messages');
}
};
I'm registering my models and associations using Sequelize CLI out of the box code when you run sequelize-cli init:
const fs = require('fs');
const path = require('path');
const Sequelize = require('sequelize');
const basename = path.basename(__filename);
const env = process.env.NODE_ENV || 'development';
const config = require(__dirname + '/../config/config.json')[env];
const db = {};
let sequelize;
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable], config);
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config);
}
fs
.readdirSync(__dirname)
.filter(file => {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(file => {
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes);
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if (db[modelName].associate) {
db[modelName].associate(db);
}
});
const User = require('./user')(sequelize, Sequelize.DataTypes)
const Message = require('./message')(sequelize, Sequelize.DataTypes)
db.models = { User, Message }
db.sequelize = sequelize;
db.Sequelize = Sequelize;
db.DataTypes = Sequelize.DataTypes
module.exports = db;
Finally, when I run findAllWithMessages(), I'm getting this error UnhandledPromiseRejectionWarning: SequelizeEagerLoadingError: Message is not associated to User!
I can confirm that the models are being created and that the association between the models work because when I run a raw SQL query select * from "Messages" as a inner join "Users" as b on b.id = a."userId" where a."userId"=1; I get the correct results. So I'm assuming its a Sequelize thing.
Any help is appreciated!
I've found my issue. In the code I was importing from db.models = { User, Message } so this block Object.keys(db).forEach(modelName)... wasn't associating the models I was using. Essentially, I was calling the .associate function on instances of the models that were different than the instances I was using.
My app is running nodejs 10.16 and sequelizejs 5.7 with postgresql 11. The initial connection is setup as:
const Sql = require("sequelize");
const db = new Sql('mydb', 'postgres', `${process.env.DB_PASSWORD}`, {
host: 'localhost',
dialect: 'postgres',
port:5432,
} );
A Group model is defined as:
const Joi = require('#hapi/joi');
const Sql = require('sequelize');
const db = require("../startup/db");
const Group = db.define('group', {
name: {type: Sql.STRING,
allowNull: false,
min: 1,
max: 50,
required: true,
},
owner_id: {
type: Sql.INTEGER,
allowNull: false,
required: true,
},
status: {type: Sql.STRING,
allowNull: false,
isIn: ['active', 'inactive']
},
last_updated_by_id: {type: Sql.INTEGER},
createdAt: Sql.DATE,
updatedAt: Sql.DATE
}, {
indexes: [
{
fields: ['name', 'owner_id']
}
]
});
function validateGroup(group) {
const schema = Joi.object({
name: Joi.string()
.min(1)
.max(50)
.required()
.trim(),
status: Joi.string()
.required()
.trim(),
});
return schema.validate(group, {allowUnknown: true});
};
module.exports.Group = Group;
module.exports.validateGroup = validateGroup;
Here is the in router /group/new to save a new group:
router.post('/new', async (req, res) => {
const { err } = validateGroup(req.body);
if (err) return res.status(400).send(err.details[0].message);
let group = Group.build(_.pick(req.body, ['name', 'status']));
group.owner_id = req.user.id;
group.last_updated_by_id = req.user.id;
let grpmember = new Groupmember({owner_id: req.user.id});
try {
await db.transaction(async () => {
await group.save();
grpmember.group_id = group.id;
await grpmember.save();
return res.status(200).send(`${group.name}-已经保存!`);
});
} catch (err) {
console.log("error in saving new group ", err);
return res.status(400).send('保存错误,请再试一遍!');
};
});
Here is the Group table output which contains both empty and non-empty name:
Why the validation for name field, such as allowNull:false and required: true did not validate the input value?
The following is the code that works:
const Group = db.define('group', {
name: {type: Sql.STRING,
validate: {
len:{
args:[1,50],
msg:"Name between 1 to 50 chars"
} ,
}
},
owner_id: {
type: Sql.INTEGER,
validate: {
isInt: true,
},
},
status: {type: Sql.STRING,
validate: {
isIn: ['active', 'inactive'],
},
},
group_data: {
type: Sql.JSONB
},
last_updated_by_id: {type: Sql.INTEGER},
fort_token: {type: Sql.STRING,
validate: {
min:20, //64 for production
},
},
createdAt: Sql.DATE,
updatedAt: Sql.DATE
}
I have a User-table and a userAttributes table. Every user can only have one instance of each userAttribute, so I would like to create a composite unique index for the columns name and userId(That is created by userAttributes.belongsTo.) How can this be done?
UserAttribute = sequelize.define('userAttributes', {
name: {
type: Sequelize.STRING,
allowNull: false,
unique: 'nameIndex',
validate: {
isIn: [['phone', 'name','driverRequest']],
}
},
value: {
type: Sequelize.STRING,
allowNull: false
},
});
User.hasMany(userAttributes, {unique: 'nameIndex'});
userAttributes.belongsTo(User, {unique: 'nameIndex'});
I tride adding the unique nameIndex with no success, it seems to only apply to the name-column.
var Sequelize = require('sequelize');
var sequelize = new Sequelize('<yourDatabaseName>', '<yourUserName>', '<yourPassword', {
host: '<ip>'
});
var User = sequelize.define('user', {
id: {
type: Sequelize.STRING,
allowNull: false,
primaryKey: true
},
});
var UserAttribute = sequelize.define('userattribute', {
userId: {
type: Sequelize.STRING,
allowNull: false,
unique: 'compositeIndex',
references: {
model: User,
key: "id"
}
},
name: {
type: Sequelize.STRING,
allowNull: false,
unique: 'compositeIndex'
}
});
User.hasOne(UserAttribute, {
as: "UserAttribute"
})
UserAttribute.belongsTo(User, {
foreignKey: "userId",
as: 'UserId'
})
sequelize.sync({
// use force to delete tables before generating them
force: true
}).then(function() {
console.log('tables have been created');
return User.create({
id: 'randomId1'
});
})
.then(function() {
console.log('tables have been created');
return User.create({
id: 'randomId2'
});
})
.then(function() {
return UserAttribute.create({
userId: 'randomId1',
name: 'name1'
});
})
.then(function() {
return UserAttribute.create({
userId: 'randomId2',
name: 'name1'
});
})
// // generates Validation Error
// .then(function() {
// return UserAttribute.create({
// userId: 'randomId1',
// name: 'name1'
// });
// })
I'm using Sequelize connected to PostgreSQL and as I want to use sync function I would like to prepare valid models to create tables on every environment.
EDIT:
Wallet:
'use strict';
module.exports = function(db, DataTypes) {
var Wallet = db.define('Wallet', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
money: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
}
createdAt: DataTypes.DATE,
updatedAt: DataTypes.DATE
}, {
tableName: 'wallet',
classMethods:{
associate : function( models ) {
Wallet.belongsTo( models.User,{ foreignKey : 'id_user'});
}
}
});
return Wallet;
};
User:
'use strict';
var bcrypt = require('bcrypt-nodejs');
var crypto = require('crypto');
var moment = require('moment');
var models = require('./');
var afterCreateHook = function(user, options, fn) {
models.Wallet.build({id_user: user.id}).save();
fn(null, user);
};
module.exports = function(db, DataTypes) {
var User = db.define('User', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
password: DataTypes.STRING,
email: {
type: DataTypes.STRING,
unique: true,
allowNull: false,
isEmail: true
},
login: {
type: DataTypes.STRING,
unique: true,
allowNull: false
}
}, {
tableName: 'pl_users',
instanceMethods: instanceMethods,
classMethods: {
associate : function( models ) {
User.hasOne( models.Wallet);
}
},
hooks: {
afterCreate: afterCreateHook
}
});
return User;
};
Why
models.Wallet.build({id_user: user.id}).save();
is not working? Account is creating and then I want to create wallet with specific user_id. I don't have even an error...
Help please!
You should check relations from sequelize docs
In your case youu need to define:
Wallet.belongsTo(User,{foreignKey: 'id_user'});
This will add id_user to Wallet model , so you dont need to specify id_user attribute in your WalletModel.
If you are using sequelize import function , you should add the relation in "associate" class method like this:
module.exports = function(db, DataTypes) {
var Wallet = db.define('Wallet', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
allowNull: false,
primaryKey: true
},
pin: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 0
},
money: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: 0
},
createdAt: DataTypes.DATE,
updatedAt: DataTypes.DATE
}, {
tableName: 'Wallet',
classMethods:{
associate : function( models ) {
Wallet.belongsTo( models.User,{ foreignKey : 'id_user'});
}
}
});