I am using Sequelize for PostgresSQL. For example: I've got two tables Friendship and User. To make friendship possible for every user, I've got two relations n:n.
Associations in Sequelize
User.hasMany(Friendship,
{
as: "friendshipsAsked",
foreignKey: "asked_user_id",
joinTableName: "friendship"
});
User.hasMany(Friendship,
{
as: "friendshipsAsking",
foreignKey: "asking_user_id",
joinTableName: "friendship"
});
Friendship.belongsTo(User,
{
...
});
Friendship.belongsTo(User,
{
...
});
My biggest problem is querying friendships for user. When I've got user model, I have to get user.getFriendshipsAsking() and user.getFriendshipsAsked() and then merge both.
Is there any possibility to change relations so I can have user.getFriendships() in SQL such that it will perform like SELECT * FROM frienships WHERE requesting_user_id = 'user.id' OR requested_user_id = 'user.id'?
I would like to have a better solution to model friendship between users in the database?
Related
I am creating two models, the first one is User and the second one is Portfolio. When a user is creating a Portfolio (where a user can only have one Portfolio), I want it to have reference to the user who is creating it, and every time that user's data is fetched, I want it to also fetching their portfolio data if any.
I am trying to use hasOne to create portfolio_id inside User tables, with the skeleton generated using sequelize init command, but it is not working. I cannot find a column the name protfolio_id if I don't put it inside the user migration file. Is that how it is supposed to be?
How should I design the models? Should I include the portfolio_id in User tables and include user_id in Portfolio table, or is there a best way to do it?
And which associations method should I use, hasOne or belongsTo?
First of all make sure that you are calling Model.associate for each model. This will run queries for all the relationships.
You can define the relationships in the associate method as follows:
// user.js (User Model definition)
module.exports = (sequelize, dataTypes) => {
const { STRING } = dataTypes
const User = sequelize.define("user", {
username: { type: STRING }
})
User.associate = models => {
User.hasOne(models.Portfolio, { foreignKey: "userId" }) // If only one portfolio per user
User.hasMany(models.Portfolio) // if many portfolios per user
}
return User
}
// portfolio.js (Portfolio Model definition)
module.exports = (sequelize, dataTypes) => {
const { STRING } = dataTypes
const Portfolio = sequelize.define("portfolio", {
portfolioName: { type: STRING }
})
Portfolio.associate = models => {
Portfolio.belongsTo(models.User, { foreignKey: "userId" })
}
return Portfolio
}
hasOne stores the foreignKey in the target model. So this relationship will add a foreign key userId to the Portfolio model.
belongsTo stores the key in the current model and references the primary key of the target model. In this case the Portfolio.belongsTo will add userId in the Portfolio model which will reference the primary key of User model.
Notice how both these relationships do the same thing, they add userId to the Portfolio model. Its better to define this in both models for your last use case:
I want it to have reference to the user who is creating it, and every time that user's data is fetched, I want it to also fetching their portfolio data if any.
Accessing related models:
In sequelize fetching a related model together with the main model is called Eager Loading. Read more about it here.
Now for your use case if you want to fetch the portfolio if any, while fetching user, do the following:
var userWithPortfolio = await User.findAll({include: [models.Portfolio]};
// Or you may also use include: {all: true} to include all related models.
var userWithPortfolio = await User.findAll({include: {all: true}};
/*
Output:
userWithPortfolio = {
username: "xyz",
portfolio: {
portfolioName: "xyz"
}
}
*/
I am a new one working in Sequelize. I do not know how to change the query to sequelize
SELECT a.* FROM employees a,emp_dept_details b where b.Dept_Id=2 AND a.Emp_No = b.Emp_Id
Emp_No is Primary Key in Employee table
EmpDeptDetails.hasMany(Emp, {foreignKey: 'Emp_No'})
Emp.belongsTo(EmpDeptDetails, {foreignKey: 'Emp_No'})
I am not sure but try out the below query
Assuming
You have the relationships between the 2 tables defined in the models class.
You have Model Employee for employees table and EmployeeDeptDetails for emp_dept_details table. Change them to your respective names before trying.
Employee.findAll({
include: [{
model: EmployeeDeptDetails,
where: { Emp_Id: Sequelize.col('employees.Emp_No'), Dept_Id: 2 }
}]
});
Is it possible to make an association in sequelize from a model with a column which is array of json
timeLine:[
{
userId:2,
status:Started
},
{
userId:3,
status:Ended
}
]
timeLine is a column in case table.
I want a cases which was started by given user.
On a high level you need to create two models.
User
Case
User would have a foreign key id to the Case table.
Next in the Case model, establish a one-to-many relationship so that you can do a Case.timeline to pull up the array of users.
// example of how to establish the one-to-many relationship
Case.hasMany(models.user, {
as: 'timeline',
foreignKey: {
name: 'caseId',
allowNull: false
}
});
So there are a lot of answers that explain how you model a Many-to-Many relationship in sequelizejs using hasMany() etc. But none of them has explained how and where do you store attributes which are created due to such an association, for eg: A customer can belong to or have many merchants and a merchant can have many customers, one such attribute of this relationship is a unique customer_id for a particular merchant-cutomer. Now where should this key(and any other detail) reside if we follow this: Stackoverflow answer
If you want additional attributes in your join table, you can define a model for the join table in sequelize, before you define the association, and then tell sequelize that it should use that model for joining, instead of creating a new one:
Customer = sequelize.define('customer', {})
Merchant = sequelize.define('merchant', {})
MerchantCustomers = sequelize.define('merchant_customers', {
customer_id: DataTypes.INTEGER
})
Merchant.belongsToMany(Customer, { through: MerchantCustomers })
Customer.belongsToMany(Merchant, { through: MerchantCustomers })
customer.addMerchant(merchant, { customer_id: 42 })
http://docs.sequelizejs.com/en/latest/docs/associations/#belongs-to-many-associations
To access the join table attributes:
c.getMerchants().then(function (merchants) {
merchants[0].merchant_customer.customer_id // Or perhaps merchant_customers, can't remember
});
I have a database with three primary tables: users, teams, and folders joined by two junction tables, users_teams and teams_folders. There is a many-to-many relationship between users and teams and between teams and folders (a user can be on more than one team and teams can own more than one folder).
Sequelize does a wonderful job of managing the user-teams and teams-folder relationship, but I can find no way to establish a relationship between users and folders.
Is there any way to join across two junction tables without resorting to raw SQL?
There seems to be no way to accomplish this elegantly or in a reasonable number of steps. I have tried methods like user.getFolders(), Folder.findAll({ include: [User] }), but Sequelize doesn't seem to be able to understand a three level hierarchy.
Assuming the following relations:
User.belongsToMany(Team, { through: 'users_teams'});
Team.belongsToMany(User, { through: 'users_teams'});
Folder.belongsToMany(Team, { through: 'teams_folders'});
Team.belongsToMany(Folder, { through: 'teams_folders'});
You should be able to load everything in one go using nested includes:
User.findAll({
include: [
{
model: Team,
include: [
Folder
]
}
]
});
You seem to be on the right track already with the example you have given in your post :). The only thing you need to change is instead of passing the User model directly in include, you pass an object with a model property and a further nested include property
Pay attention to following:
Define relations in both directions
Check you have foreignKey, otherKey in correct order
User.belongsToMany(Team, {
through: 'users_teams',
foreignKey: 'user_id',
otherKey: 'team_id'
});
Team.belongsToMany(User, {
through: 'users_teams',
foreignKey: 'team_id',
otherKey: 'user_id'
});