I am new to Sails and creating a simple application.
I am stuck with data model now.
User model is as follows:
module.exports = {
attributes: {
firstName: {
type: 'string'
},
lastName: {
type: 'string'
},
email: {
type: 'email',
required: true
},
password: {
type: 'String'
},
passwordSalt: {
type: 'String'
},
projects:{
collection: 'ProjectMember',
via: 'userId'
}
}
};
I need one more Model called TinyUser which gets some of attributes from User (Like Foreign key to User), so that I can access TinyUser instead of accessing User directly.
TinyUser Model is as follows:
module.exports = {
tableName: 'User',
attributes: {
firstName:{
type: 'string'
},
lastName: {
type: 'string'
},
email: {
type: 'email'
}
}
};
ProjectMember model is as follows:
module.exports = {
attributes: {
projectId: {
model: 'Project'
},
userId: {
model: 'TinyUser'
},
projectRole: {
model: 'ProjectRole'
},
}
};
In Sails, Is there anyway I can save data in TinyUser without actually creating but just holding some of attributes of User table data?
To Make it clear, If there is another table called Task and it is trying to access user data then TinyUser is better option as a model rather than User as it holds only required info. for task rather than storing all other fields which User does.
Is there any way I can fix this?
Thanks In Advance
Do you mean you need to have the "TinyUser" inherited from the "User" model?
You can do it like this.
/api/services/baseUserModel.js:
module.exports = {
attributes: {
firstName: 'string',
lastName: 'string',
email: {
type: 'email',
required: true
},
password: 'string',
passwordSalt: 'string',
projects: {
collection: 'ProjectMember',
via: 'userId'
}
}
};
/api/models/TinyUser.js:
var baseUserModel = require('../services/baseUserModel'),
_ = require('lodash');
module.exports = _.merge({
tableName: 'User',
attributes: {
firstName: 'string',
lastName: 'string',
email: {
type: 'email',
required: true
}
}
}, baseUserModel);
And the ProjectMember model should be:
module.exports = {
attributes: {
projectId: {
model: 'project'
},
userId: {
model: 'tinyuser'
},
projectRole: {
model: 'projectrole'
}
}
};
Related
I'm using Sequelize to create an instance of Many-to-Many relationship, but it not working.
First, I have a model with two class as below:
Room:
Room.init({
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: DataTypes.UUIDV4,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
}, { sequelize, modelName: "Room" }
);
User:
User.init(
{
id: {
type: DataTypes.UUID,
primaryKey: true,
defaultValue: DataTypes.UUIDV4,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
},
{ sequelize, modelName: "User"}
);
UserRoom:
UserRoom.init("UserRoom", { sequelize });
Relationship:
User.belongsToMany(Room, { as:'container', through: UserRoom, foreignKey: "userId" });
Room.belongsToMany(User, { as:'joiners', through: UserRoom, foreignKey: "roomId" });
And the UserRoom has another key with Message Model:
UserRoom.belongsTo(Message, { as: "lastReadMessage" });
Ok, now when i create a new Room with code:
const room = await Room.create(
{
name: name,
avatarId: avatarUri,
joiners: [
{
id: '1',
},
{
id: '2',
},
],
},
{
include: [{ association: User, as: 'joiners' }],
}
);
I get an error:
TypeError: Cannot read properties of undefined (reading 'name')
I don't know why error, I try this example but it still wrong.
My question is: How I create object and link to another relationship?
UPDATE
Now, I can run it with below code:
const room = await Room.create({
name: name,
avatarId: avatarUri,
});
await UserRoom.bulkCreate(
[
{
lastReadMessageId: null,
userId: 1,
roomId: room.id,
},
{
lastReadMessageId: null,
userId: 2,
roomId: room.id,
},
]
);
You're trying to create users with id equals to 1 and 2 along with creating a room. If you wish to associate existing users with a new room then you need to call addJoiners of a new room model:
const room = await Room.create(
{
name: name,
avatarId: avatarUri,
);
// pass user instances or ids.
await room.addJoiners([1,2])
Recently we moved to Sequelize ORM from Knex due to which we have existing database to which models are map to . Everything working fine except model relationships.
So I have a users table and roles table. Each user can have one role but each role can be assigned to many users. To map these to models, I created model files that is as follows.
User Model:
const Sequelize = require('sequelize');
const sequelize = require('../utility/dbConnection');
const roles = require('./Roles');
module.exports = sequelize.define("User", {
id: {
type: Sequelize.INTEGER(11),
primaryKey: true,
autoIncrement: true,
allowNull: false
},
firstName: Sequelize.STRING(255),
middleName: Sequelize.STRING(255),
lastName: Sequelize.STRING(255),
email: {
type: Sequelize.STRING(255),
unique: true
},
phoneNumber: {
type: Sequelize.STRING(255),
unique: true
},
is_phonenumber_verified: {
type: Sequelize.BOOLEAN,
default: false
},
is_email_verified: {
type: Sequelize.BOOLEAN,
default: false
},
roleID: {
type: Sequelize.INTEGER
},
password: Sequelize.STRING(255)
// }, {
// defaultScope: {
// attributes: { exclude: ['password'] }
// }
}, {
tableName: 'users'
},{
classMethods: {
associate: function() {
this.hasOne(roles,{foreignKey: 'roleID'})
}
}
}
);
roles Model:
const Sequelize = require('sequelize');
const sequelize = require('../utility/dbConnection');
module.exports = sequelize.define("Role", {
id: {
type: Sequelize.INTEGER(11),
primaryKey: true,
autoIncrement: true,
allowNull: false
},
name: {
type: Sequelize.STRING(255),
unique: true
},
},{
tableName: 'roles'
});
Now in the controller file, I want to fetch user details and role name for which code snippet are as follows
const userModel = require('../../models/Users');
const rolesModel = require('../../models/Roles');
let user = await userModel.findOne({ where: { email: req.body.email } },{include:[{model:rolesModel}]});
The problem is it only fetches rolesID from the Users table but not roles name from roles table .
Can anyone help me on this what I am doing wrong here ?
You have To Write Your Include Condition Like This
const userModel = require('../../models/Users');
const rolesModel = require('../../models/Roles');
let user = await userModel.findOne({
where: {
email: req.body.email
},include:
[{ model: rolesModel }]
});
you can use belongsTo relation instead of using hasOne
add this relation in roles table and remove from users table
classMethods: {
associate: function() {
this.belongsTo(users,{foreignKey: 'roleID'})
}
}
You can see this Sequelize Associations docs to know more about Associations and relations
I have two models using mongoose as shown below:
Teams
var mongoose = require('mongoose');
var teamsSchema = new mongoose.Schema({
Name: {
type: String,
required: true,
unique: true
},
Description: {
type: String
},
Is_Active: {
type: String,
enum: ["Y", "N"],
default: 'Y'
}
}, { timestamps: true });
module.exports = mongoose.model('teams', teamsSchema);
Users
var mongoose = require('mongoose');
var usersSchema = new mongoose.Schema({
First_Name: {
type: String
},
Last_Name: {
type: String
},
Email: {
type: String,
required: true,
unique: true
},
Teams: [{ type: mongoose.Schema.Types.ObjectId, ref: 'teams' }],
Is_Active: {
type: String,
enum: ["Y", "N"],
default: 'Y'
}
}, { timestamps: true });
module.exports = mongoose.model('users', usersSchema);
We would like to migrate from MongoDB to PostgreSQL and we are using sequelize and created models as below
Teams
'use strict';
const { Model } = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class teams extends Model {
static associate(models) {
// define association here
}
};
teams.init({
Name: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
Description: DataTypes.STRING,
Is_Active: {
type: DataTypes.ENUM,
values: ['Y', 'N'],
defaultValue: 'Y'
}
}, {
sequelize,
modelName: 'teams',
});
return teams;
};
Users
'use strict';
const { Model } = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class users extends Model {
static associate(models) {
// define association here
}
};
users.init({
First_Name: DataTypes.STRING,
Last_Name: DataTypes.STRING,
Email: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
Teams: {
type: DataTypes.ARRAY(DataTypes.INTEGER)
},
Is_Active: {
type: DataTypes.ENUM,
values: ['Y', 'N'],
defaultValue: 'Y'
}
}, {
sequelize,
modelName: 'users',
});
return users;
};
With mongoose, we could able to get the User details along with Teams and Teams along with Users. How to associate a model in sequelize with an array of keys? How to write queries(find/join) in Sequelize with an array of foreign keys.
Once this is resolved, we need to think of nested arrays.
Defining associations between models are very simple, as you can find it here.
I can see that you already have the associate method in each model.
You should add this in each method in order to have the correct associations:
Teams
this.belongsToMany(models.users, { through: 'TeamUsers' });
Users
this.belongsToMany(models.teams, { through: 'TeamUsers' });
Also, you don't need the Teams property in the Users model, since many-to-many associations exploit an external table in relational databases.
Here is an example of how to include users when querying for teams:
models.teams.find({
include: models.users
}).then(foundTeamsWithUsers => {
// Handle here your teams: use users to access the list of users related to each team
}).catch(handleErrorFunction);
You can find more examples about eager loading with sequelize.
I have two models
1.PageType Model
module.exports = (mongoose) => {
const pageTypeSchema = new mongoose.Schema({
title: {
type: String,
key: {
type: String,
required: true,
},
}, {
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' },
});
return mongoose.model('PageType', pageTypeSchema);
};
WorkFlow Model
module.exports = (mongoose) => {
const workFlowSchema = new mongoose.Schema({
title: {
type: String,
default: null,
},
key: {
type: String,
default: null,
},
level: {
type: Number,
required: true,
},
page_type_id: {
type: mongoose.Schema.Types.ObjectId,
ref: 'PageType',
},
}, {
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' },
});
return mongoose.model('WorkFlow', workFlowSchema);
};
But when I try to use populate it throws Schema hasn't been registered for model PageType
async getFlowById(flowId) {
const result = await this.workFlow.findById(flowId).populate('page_type_id').exec();
return result;
}
Can anyone please help me with this??
In app.js the models are included before routes also PageType model is also declared before WorkFlow model
You typed wrong collection name. Collection name is Workflow and you are trying to findById at workflow. So i think Workflow should be there. Just try with that.
I'm using nodejs v8.9.0 + expressjs v4.14.0 + sequelize v3.25.0 to build a web app in which people can publish articles.
I have these models
/** ARTICLE MODEL **/
module.exports = function(sequelize, DataTypes) {
var Article = sequelize.define('articles', {
title: {
type: DataTypes.STRING(255),
field: 'title'
},
content: {
type: DataTypes.TEXT,
field: 'content'
}
anonymous: {
type: DataTypes.BOOLEAN,
field: 'anonymous'
}
},
{
classMethods: {
Article .belongsTo(
models.users,
{
foreignKey: 'userId'
}
);
}
})
And
/** USER MODEL **/
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('users', {
firstName: {
type: DataTypes.STRING(50),
field: 'firstName'
},
lastName: {
type: DataTypes.STRING(200),
field: 'lastName'
},
email: {
type: DataTypes.STRING(200),
field: 'email'
},
},
{
classMethods: {}
})
Users can publish articles anonymously or not
Now when I'm querying articles list, I want to include User model only if anonymous is false.
How to do that ?
Not so elegant solution, but work:
Article.findAll({
include: [{
model: User,
required: false,
where: sequelize.where(sequelize.literal('anonymous'), false)
}],
})