Squelize: how to use junction table to create other associates? - javascript

I have three basic tables A, B and C. A and B have many-to-many relation. So I use junction table of A_B. C has one-to-many relation to A_B. This is how they are defined when using sequelize.
A.associate = function(models) {
A.belongsToMany(models.B, {
through: 'A_B',
as: 'Bs',
foreignKey: 'a_id'
});
};
B is similar, then C.
C.associate = function(models) {
C.hasMany(models.A_B, {
as: 'ABs',
foreignKey: 'c_id'
});
};
But when I run it, I get the following message.
Error: C.hasMany called with something that's not a subclass of Sequelize.Model
It looks like sequelize does not recognize A_B as valid. Any way to solve?
Thanks.

If you want to fetch lines of the A_B table, then you need to create a model representing it (it won't be "created" in sequelize when you declare the association in A with through).
Assumptions :
your table A_B has three columns a_id, b_id and c_id
The code should look something like :
const A = sequelize.define('A', {
id: Sequelize.STRING
})
A.associate = function(models) {
A.belongsToMany(models.B, {
through: {
model: 'A_B',
},
as: 'Bs',
foreignKey: 'a_id',
otherKey: 'b_id'
});
}
const B = sequelize.define('B', {
id: Sequelize.STRING
})
B.associate = function(models) {
B.belongsToMany(models.A, {
through: {
model: 'A_B',
},
as: 'As',
foreignKey: 'b_id',
otherKey: 'a_id'
});
}
const A_B = sequelize.define('A_B', {
a_id: Sequelize.STRING,
b_id: Sequelize.STRING,
c_id: Sequelize.STRING
})
const C = sequelize.define('C', {
id: Sequelize.STRING
})
C.associate = function(models) {
C.hasMany(models.A_B, {
as: 'ABs',
foreignKey: 'c_id'
});
}

Related

Complex queering in the Sequelize (include, order, limit)

I have 3 models
module.exports = (sequelize, DataTypes) => {
class User extends Model {
static associate({ Chat, Message }) {
this.belongsToMany(Chat, {
through: 'UsersChats',
foreignKey: 'userId',
as: 'chats'
});
this.hasMany(Message, { as: 'messages', foreignKey: 'userId' });
}
}
User.init(
{
login: {
type: DataTypes.STRING,
allowNull: false,
unique: true
},
password: {
type: DataTypes.STRING,
allowNull: false
}
},
{
sequelize,
modelName: 'User'
}
);
return User;
};
module.exports = (sequelize, DataTypes) => {
class Chat extends Model {
static associate({ Message, User }) {
this.hasMany(Message, { as: 'messages', foreignKey: 'chatId' });
this.belongsToMany(User, {
through: 'UsersChats',
foreignKey: 'chatId',
as: 'users'
});
}
}
Chat.init(
{
name: DataTypes.STRING
},
{
sequelize,
modelName: 'Chat'
}
);
return Chat;
};
module.exports = (sequelize, DataTypes) => {
class Message extends Model {
static associate({ Chat, User }) {
this.belongsTo(Chat, { foreignKey: 'chatId', as: 'chat' });
this.belongsTo(User, { foreignKey: 'userId', as: 'user' });
}
}
Message.init(
{
userId: DataTypes.UUID,
text: DataTypes.TEXT,
chatId: DataTypes.UUID
},
{
sequelize,
modelName: 'Message'
}
);
return Message;
};
I'm trying to build a query like this for getting a list of chats, ordered by creation and limited by a last message
select C.name,
C.id,
M.text,
M."userId"
from "Chats" as C
left join lateral (
select text,
"userId",
"createdAt"
from "Messages" M
where M."chatId" = C.id
order by "createdAt" DESC
limit 1
) M on true
order by M."createdAt" DESC;
Sequelize query
Chat.findAll({
include: [
{
model: User,
as: 'users',
through: {
where: {
id: userId
}
}
},
{
model: Message,
as: 'messages',
limit: 1,
order: [['createdAt', 'DESC']]
}
],
order: [['messages', 'createdAt', 'DESC']]
});
But when Execute a query, I got an exception
SELECT "Chat"."id", "Chat"."name", "Chat"."createdAt", "Chat"."updatedAt", "users"."id" AS "users.id", "users"."login" AS "users.login", "users"."password" AS "users.password", "users"."createdAt" AS "users.createdAt", "users"."updatedAt" AS "users.updatedAt", "users->UsersChats"."createdAt" AS "users.UsersChats.createdAt", "users->UsersChats"."updatedAt" AS "users.UsersChats.updatedAt", "users->UsersChats"."chatId" AS "users.UsersChats.chatId", "users->UsersChats"."userId" AS "users.UsersChats.userId" FROM "Chats" AS "Chat" LEFT OUTER JOIN ( "UsersChats" AS "users->UsersChats" INNER JOIN "Users" AS "users" ON "users"."id" = "users->UsersChats"."userId" AND "users->UsersChats"."id" = 'a529cfbd-4104-4ed8-b135-443de9d3b41a') ON "Chat"."id" = "users->UsersChats"."chatId" ORDER BY "messages"."createdAt" DESC;
DatabaseError [SequelizeDatabaseError]: missing FROM-clause entry for table "messages"
I know, that the issue in this order: [['messages', 'createdAt', 'DESC']], but I need order by last messages. What can I do, any ideas?

querying for a record and its associations with sequelize

Given a table Show and a table Venue, with the below associations:
Show.belongsTo(Venue, { foreignKey: { name: 'id_venue', allowNull: false } });
Venue.hasMany(Show);
I'm trying to grab one venue and all of its associated shows.
const getSingleVenue = async (req, res) => {
try {
const { venueName } = req.params;
const venue = await Venue.findOne({
where: {
name: venueName,
},
include: [
{ model: Show }
]
})
res.send(venue);
}
catch(err) {
console.log(err);
res.send(400);
}
}
Right now, I'm stuck on the error Unknown column 'show.venueId' in 'field list'.
Not sure how to edit my associations to give sequelize what it's looking for.
The problem is this Venue.hasMany(Show); Y're not defined the foreign key.
Replace some code :
Show.belongsTo(Venue, { foreignKey: { name: 'id_venue', allowNull:
false } }); Venue.hasMany(Show);
By
Show.belongsTo(Venue, { foreignKey: { name: 'id_venue', allowNull: false } });
Venue.hasMany(Show, { foreignKey: { name: 'id_venue', as: shows } };

How to properly use nested include query with sequelize in nodes(mysql)

How to properly use nested include query with sequelize(nodejs)
my nested include query with sequelize is giving me this error
"category is associated to course using an alias. You've included an alias (Category), but it does not match the alias defined in your association."
what i want is from the users list, i want to get all the tcourses, then from that, i will get all the courses then from that i want to get the list of all the categories
I don't know what I did that is wrong, I just need it to work, am still new to nodejs
here is the code
export default {
Query: {
users: combineResolvers(isAdmin, async (parent, args, { models }) => {
return await models.User.findAll();
}),
},
User: {
messages: async (user, args, { models }) => {
return await models.Message.findAll({
where: { userId: user.id },
});
},
tcourses: async (user, args, { models }) => {
return await models.TCourses.findAll({
where: { UserId: user.id },
include: [{model: models.Course, as: 'Course', include: [{model: models.Category, as: 'Category'}]}]
})
}
},
}
here is my tcourses model code
const tcourses = (sequelize, DataTypes) => {
const TCourses = sequelize.define('tcourses', {
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
unique: true,
primaryKey: true,
field: 'id'
},
}, {
timestamps: false
});
TCourses.associate = models => {
TCourses.belongsTo(models.Course,{ as: 'Course', required: false})
TCourses.belongsTo(models.User,{ as: 'User'})
};
return TCourses;
};
export default tcourses;
here is my Course model code
const course = (sequelize, DataTypes) => {
const Course = sequelize.define('course', {
Title: {
type: DataTypes.STRING,
validate: {
notEmpty: {
args: true,
msg: 'Enter Course Title'
}
},
},
}, {
timestamps: false
})
Course.associate = models => {
Course.belongsTo(models.Category, { as: 'Cat'})
Course.hasMany(models.Requirements,{onDelete: 'CASCADE', foreignKey: 'CourseId'})
Course.belongsTo(models.User, { as: 'Owners'})
Course.hasMany(models.Audience,{onDelete: 'CASCADE', foreignKey: 'CourseId'})
Course.hasMany(models.TCourses,{onDelete: 'CASCADE', foreignKey: 'CourseId'})
};
return Course
};
export default course
here is my Category model code
const category = (sequelize, DataTypes) => {
const Category = sequelize.define('category', {
catName: {
type: DataTypes.STRING,
validate: {
notEmpty: {
args: true,
msg: 'Enter Category name'
}
},
},
}, {
timestamps: false
});
Category.associate = models => {
Category.hasMany(models.Course,{onDelete: 'CASCADE', foreignKey: 'CatId'})
Category.hasMany(models.TCategory,{onDelete: 'CASCADE', foreignKey: 'CategoryId'})
};
return Category;
};
export default category;
pls how can i make it to work
You have to provide the same alias for model in both include statement and while defining association.
The error also specifies the same,
"category is associated to course using an alias. You've included an alias (Category), but it does not match the alias defined in your association."
While querying the DB you have specified the alias for category table as Category
models.TCourses.findAll({
where: { UserId: user.id },
include: [{model: models.Course, as: 'Course', include: [{model: models.Category, as: 'Category'}]}]
})
In the Course model you have defined the association as Cat
Course.belongsTo(models.Category, { as: 'Cat'})
Now you have to make it same, i,e use either Cat or Catgory at both the places.

node Sequelize how to write static functions

I have experience in writing statics functions in moongose like
var mongoose =require('mongoose');
var Schema = mongoose.Schema;
var adminSchema = new Schema({
fullname : String,
number : Number,
email: String,
auth : {
username: String,
password : String,
salt: String
}
});
adminSchema.statics.usernameInUse = function (username, callback) {
this.findOne({ 'auth.username' : username }, function (err, doc) {
if (err) callback(err);
else if (doc) callback(null, true);
else callback(null, false);
});
};
here usernameInUse is the function I wana write but using sequelize for mysql database
my model
/*
This module is attendant_user table model.
It will store attendants accounts details.
*/
"use strict";
module.exports = function(sequelize, DataTypes) {
var AttendantUser = sequelize.define('AttendantUser', {
username : {
type : DataTypes.STRING,
allowNull : false,
validate : {
isAlpha : true
}
},{
freezeTableName : true,
paranoid : true
});
return AttendantUser;
};
How to add statics function here..??
Well, you can easily use Expansion of models
var User = sequelize.define('user', { firstname: Sequelize.STRING });
// Adding a class level method
User.classLevelMethod = function() {
return 'foo';
};
// Adding an instance level method
User.prototype.instanceLevelMethod = function() {
return 'bar';
};
OR in some cases you may use getter and setter on your models. See the docs:
A) Defining as part of a property:
var Employee = sequelize.define('employee', {
name: {
type : Sequelize.STRING,
allowNull: false,
get : function() {
var title = this.getDataValue('title');
// 'this' allows you to access attributes of the instance
return this.getDataValue('name') + ' (' + title + ')';
},
},
title: {
type : Sequelize.STRING,
allowNull: false,
set : function(val) {
this.setDataValue('title', val.toUpperCase());
}
}
});
Employee
.create({ name: 'John Doe', title: 'senior engineer' })
.then(function(employee) {
console.log(employee.get('name')); // John Doe (SENIOR ENGINEER)
console.log(employee.get('title')); // SENIOR ENGINEER
})
B) Defining as part of the model:
var Foo = sequelize.define('foo', {
firstname: Sequelize.STRING,
lastname: Sequelize.STRING
}, {
getterMethods : {
fullName : function() { return this.firstname + ' ' + this.lastname }
},
setterMethods : {
fullName : function(value) {
var names = value.split(' ');
this.setDataValue('firstname', names.slice(0, -1).join(' '));
this.setDataValue('lastname', names.slice(-1).join(' '));
},
}
});
Hope it helps.
AttendantUser.usernameInUse = function (username, callback) {
...
};
return AttendantUser;

How can I get value from sequelize associated model?

I still trying to get menu_title from associated Menu model to json. If I use below described code console shows me error
ER_BAD_FIELD_ERROR: Unknown column 'Products.MenuId' in 'field list' also if I have defined {foreignKey: 'menu_id'}. What I'm doing wrong?
Menu model:
module.exports = function(sequelize, Sequelize) {
var Menu = sequelize.define("Menu", {
owner_id: Sequelize.INTEGER,
menu_title: Sequelize.STRING,
}, {
classMethods: {
associate: function(models) {
Menu.hasMany(models.Product)
}
}
});
return Menu;
};
Product model:
module.exports = function(sequelize, Sequelize) {
var Product = sequelize.define("Product", {
owner_id: Sequelize.INTEGER,
menu_id: Sequelize.INTEGER,
product_title: Sequelize.STRING,
}, {
classMethods: {
associate: function(models) {
Product.belongsTo(models.Menu, { foreignKey: 'menu_id'})
}
}
});
return Product;
};
Then inside controller:
Menu.find({
where: { owner_id: req.user.id },
include: [
{ model: Product }
]
}).success(function(match) {
res.json(match.home);
});
Thanks for any help!
You need to include the foreign key on both sides of the relation
Menu.hasMany(models.Product, { foreignKey: 'menu_id'})
Otherwise sequelize assumes that the foreign key is called menuId when querying from the menu side of the relation

Categories

Resources