How do I query in many to many relationships? e.g. There are product, category, and product_category models. Below is an association by model:
// product
product.belongsToMany (models.category, {
through: 'product_category',
foreignKey: 'product_id'
});
// category
category.belongsToMany (models.product, {
through: 'product_category',
foreignKey: 'category_id'
});
// product_category
product_category.belongsTo (models.product, {
foreignKey: 'product_id'
});
product_category.belongsTo (models.category, {
foreignKey: 'category_id'
});
I would appreciate if you can tell me which model the findAll () should have at the beginning when querying.
Yep, seems like a good fit if you are using node and sequelize it’s a pretty simple lift to put GraphQL in play and manipulate your sequelize models in your resolvers... nice to have the graphiql playground to hit your queries with.... easy peazy
Related
I have 2 table:
User
Follow
Table follow has 2 foreign keys:
follower_id
followee_id
They are both foreign key to user table
I have the following associations created:
//Users-Followers
this.follows.belongsTo(this.users, {
as: 'follower',
foreignKey: 'follower_id'
});
this.users.hasMany(this.follows, {
as: 'folower',
foreignKey: 'follower_id'
});
//Users-Followees
this.follows.belongsTo(this.users, {
as: 'folowee',
foreignKey: 'followee_id'
});
this.users.hasMany(this.follows, {
as: 'folowee',
foreignKey: 'followee_id'
});
Now I want to: get who is following who.
At the following is my query:
async function getFollowByFollower(follower_id) {
let follows = model.follows;
let users = model.users;
let follow = await follows.findAll({
include: [
{
model: users,
as: 'follower',
required: true,
where: {
id: follower_id
}
},
{
model: users,
as: 'followee',
required: true
}
]
}).catch(function(err) {
console.log('followsDAO.js getFollowByFollower error: ' + err);
});
return follow;
};
Here goes the error message:
SequelizeEagerLoadingError: users is associated to follows multiple times. To identify the correct association, you must use the 'as' keyword to specify the alias of the association you want to include.
As you can see, I have clearly indicated 'as' in both query and association.
Please help.
Thanks.
Best regards,
Never mind. My code logic is 100% correct. The problem is in the association statement I misspelled "follower" as "folower" and "followee" as "folowee".
After correcting the spelling the code is running.
There is a table called Order, Order has PK (id) and an attribute (company_id).
Other table is Company_Parameter that has PK(Id) and an attribute (cid).
I want to connect these tables on Order.company_id = Company_Parameter.cid but company_id and cid are not primary keys.
I have set an association like this in sequelize:
Order.hasMany(companyParameters, {
foreignKey: 'cid',
targetKey: 'company_id',
});
companyParameters.belongsTo(Order, {
foreignKey: 'cid',
targetKey: 'company_id',
});
but these association run:
ON Order.id =
companyParameters.cid;
I want to run
ON Order.company_id =
companyParameters.cid;
In hasMany you should use the sourceKey option to indicate other model's key and not targetKey one.
Order.hasMany(companyParameters, { foreignKey: 'cid', sourceKey: 'company_id', });
I found that if I don't put all the associations (hasMany, etc) into one file, I get the following error.
throw new Error(`${this.name}.belongsToMany called with something that's not a subclass of Sequelize.Model`);
^
Error: users.belongsToMany called with something that's not a subclass of Sequelize.Model
at Function.belongsToMany (C:\app\node_modules\sequelize\lib\associations\mixin.js:49:13)
at Object.<anonymous> (C:\app\models\/user.ts:51:6)
According to this post, this can be solved by putting all the associations into one file.
Still, I don't think it's a good approach, because
If you want to know about a model, you have to check the model definition (models/user.ts in the below example) and the association file (something like models/index.ts).
the association file can be quite huge if you have many models with associations.
How do I put a Sequelize model and its associations into the same file?
Here's what I'm trying to achieve.
// `models/user.ts`
import { Role } from './role';
const User = sequelizeInstance.define<UserInstance>(
'users', {/* fields */},
);
User.belongsToMany(Role, {
through: 'user_roles',
foreignKey: 'userId',
otherKey: 'roleId',
});
export { User };
// `model/role.ts`.
import { User } from './user';
const Role = sequelizeInstance.define<RoleInstance>(
'roles', {/* fields */}
);
Role.belongsToMany(User, {
through: 'user_roles',
foreignKey: 'userId',
otherKey: 'roleId',
});
export { Role };
Any advice will be appreciated.
Here is what I did.
I declare each model associations in the model declaration, using associate property. In your case something like:
const Role = sequelizeInstance.define<RoleInstance>(
'roles', {/* fields */}
);
Role.associate = function (models) {
Role.belongsToMany(models.users, {
through: 'user_roles',
foreignKey: 'userId',
otherKey: 'roleId',
});
});
Then in my index file, I wrote few lines to fetch all associations from models declaration and apply them:
db.roles = // assign your Role model
db.users = // assign your User model
// setup table associations
Object.keys(db).forEach(function (modelName) {
if ('associate' in db[modelName]) {
// call the associate function and pass reference to all other models
db[modelName].associate(db);
}
});
In this way I can keep a compact index, fetch and apply associations dynamically and declare associations in each model
My answer to a similar question asked a few years ago:
https://stackoverflow.com/a/67875061/11558646
Assuming the approach is sound, its advantage is that it doesn't require separate "setting-up-of-all-associations" logic.
I have multiple tables relating to each other, what i want to do now is create a many to many relationship between Document and Tag.
A single document can have many tags and a single Tag can have many Documents, How can i do this many to many relationship in sequelize?
In models/index.js i have:
Tab.sync().then(() => {
Group.sync().then(() => {
User.sync().then(() => {
Document.sync().then(() => {
Reference.sync().then(() => {
Tag.sync().then(() => {
User.hasMany(Group, {foreignKey: 'userAssigned', as: 'groups'})
Group.belongsTo(User, {foreignKey: 'userAssigned', as: 'user'})
Document.belongsTo(Group, {foreignKey: 'groupId', as: 'group'})
Group.hasMany(Document, {foreignKey: 'groupId', as: 'documents'})
Tab.hasMany(Group, {foreignKey: 'tabId', as: 'groups'})
Group.belongsTo(Tab, {foreignKey: 'tabId', as: 'tab'})
Document.hasMany(Reference, {foreignKey: 'docId', as: 'references'})
Reference.belongsTo(Document, {foreignKey: 'docId', as: 'docs'})
//trying to create many to many relationship here//
Document.hasMany(Tag)
Tag.hasMany(Document)
//---------------------//
})
})
})
})
})
})
ps: i've already read about through parameter, but i cannot understand how it would work
Many-to-many relations are described using belongsToMany in Sequelize:
// Do you already have the DocumentTag model and a table?
// I'm assuming here DocumentTag has docId and tagId fields
Document.belongsToMany(Tag, { through: DocumentTag, foreignKey: 'docId', otherKey: 'tagId' })
Tag.belongsToMany(Document, { through: DocumentTag, foreignKey: 'tagId', otherKey: 'docId' })
To get documents along with linked tags you can query like this:
const docs = await database.Document.findAll({
where: {
// here are your search conditions
},
include: [database.Tag]
})
To add tags to a certain document you can call the addTags model instance method:
const tags = await database.Tag.findAll({
where: {
// here are your search conditions
},
// to link tags to documents we don't need all attributes but `id`
attributes: ['id']
})
const doc = await database.Document.findById(documentId)
await doc.addTags(tags)
I have two tables, traders, and messages
Traders is associated to messages as following
traders.hasMany(models.messages, {as: 'sender',foreignKey : 'senderId'});
traders.hasMany(models.messages, {as: 'reciever',foreignKey : 'recieverId'});
now when I try to find trader name along with all messages using following code
ctx.body = await ctx.db.messages.findAll({
include:[{
model: ctx.db.traders,
as:'sender'
}],
attributes:['type',['data','message'],'createdAt','senderId','name'],
where:{
conversationId:ctx.request.body.conversationId
}
})
I get the following error
SequelizeEagerLoadingError: traders is not associated to messages!
Try association from both models like,
traders.hasMany(models.messages, {
as: 'sender',
foreignKey: 'senderId'
});
messages.belongsTo(models.traders, {
as: 'sender',
foreignKey: 'senderId'
});