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

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.

Related

Can Sequelize use something like a getter or setter in a find query?

For my email field, I store and query emails as lowercase strings to avoid duplicate emails like user#example.com and User#example.com. I have a set method defined in my model like:
const User = sequelize.define('user', {
email: {
type: DataTypes.STRING,
unique: { msg: 'That email is already registered.' },
validate: { isEmail: { msg: 'Invalid email.' } },
set(value) {
this.setDataValue('email', value.toLowerCase().trim())
}
}
})
This prevents setting emails with uppercase letters, but it does not prevent queries with uppercase letters. To avoid queries, I have to remember to use .toLowerCase() everywhere. It would be better if I could define it on the model so that a query like this would just work:
const user = await User.findOne({ where: { email: 'SomeEmail#example.com' } })
You can use the hooks in models to store the email in lower case.
Please have a look in below example
const createUserModel = (sequelize, { STRING, UUIDV4, UUID, DATE }) => {
const User = sequelize.define(
'User',
{
userId: {
type: UUID,
defaultValue: UUIDV4,
primaryKey: true,
},
email: {
type: STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true,
},
},
password: {
type: STRING,
allowNull: true,
},
},
{
freezeTableName: true,
timestamps: false,
hooks: {
beforeCreate: async instance => {
const email = instance.get('email');
instance.set('email', email.toLowerCase());
},
beforeUpdate: async instance => {
if (instance.changed('email')) {
const email = instance.get('email');
instance.set('email', email.toLowerCase());
}
},
},
},
);
return User;
};
module.exports = {
createUserModel,
};

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?

prisma2: how to fetch nested fields?

In prisma 1 I have used fragment to fetch the nested fields.
For example:
const mutations = {
async createPost(_, args, ctx) {
const user = await loginChecker(ctx);
const post = await prisma.post
.create({
data: {
author: {
connect: {
id: user.id,
},
},
title: args.title,
body: args.body,
published: args.published,
},
})
.$fragment(fragment);
return post;
},
};
but seems like in prisma2 it is not supported. because by running this on playground,
mutation CREATEPOST {
createPost(
title: "How to sleep?"
body: "Eat, sleep, repaet"
published: true
) {
title
body
published
author {
id
}
}
}
I am getting,
"prisma.post.create(...).$fragment is not a function",
The include option is used to eagerly load relations in Prisma.
Example from docs:
const result = await prisma.user.findOne({
where: { id: 1 },
include: { posts: true },
})
Assuming a user table with a one-to-many posts relation, this will return back the user object with the posts field as well.
Prisma also supports nesting as well, for example:
const result = await prisma.user.findOne({
where: { id: 1 },
include: {
posts: {
include: {
author: true,
}
},
},
})

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 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