I have 4 tables:
ChatRooms
Participants
Messages
Users
ChatRoom has many Participants
ChatRoom has many Messages
User has many Messages
User has Many Participants
Participant belongs to User
Message belongs to User
I'm trying to use Sequelize to query Users and under the Participants relation, I want it to return a list of 10 Participants(which is essentially the user) ordered by the ChatRoom with the most recent message. Essentially Participants would be the most recently active ChatRoms.
// My current code is:
User.findAll({
include: [
{
model: Participant,
include: [
{
model: ChatRoom,
include: [{ model: Message}]
}
],
order: [[ChatRoom, Message, 'id', 'DESC']]
}
],
})
// This is what my server is returning right now,
// but the ordering is not working:
// participantId: 2 should be on top as it has a more recent message
{
userId: 1,
name: 'Kevin',
participants: [
{
participantId: 1,
userId: 1,
chatRoomId: 1,
chatRoom:
{
chatRoomId: 1,
Messages: [{
MessageId: 1,
message: 'message1',
userId: 1
},
{
MessageId: 2,
message: 'message2',
userId: 2
}]
}
},
{
participantId: 2,
userId: 1,
chatRoomId: 2,
chatRoom:
{
chatRoomId: 2,
Messages: [{
MessageId: 3,
message: 'message3',
userId: 1
},
{
MessageId: 4,
message: 'message4',
userId: 3
}]
}
}
]
}
I don't know if what I want is possible. The important part is that the query returns the ChatRooms with the most recent messages. I don't have to do it inside the User object. I can do it in a separate query if need be and I am also open to designing the schema a different way.
I discovered that my posted code does work. The issue is that when I used limit (which I had left out for simplicities sake) it does a subquery and causes it to have a "column not found" error.
I tried a subQuery: false but it still didn't allow me to combine a limit with order.
Here you should try this.
Add > separate:true in your join with include and after that your code should be like below
User.findAll({
subQuery:false
include: [
{
model: Participant,
include: [
{
model: ChatRoom,
include: [{ model: Message}],
order: [['id', 'DESC']]
}
],
}
],
})
Related
I trying to fetch the assessment details for a class in which assessment_test model has association with student_assessment_test model(hasMany). I want the fetched result ordered according to the marks obtained by student. I am trying the below method but it doesn't seem to be working. Please let me know the correct method for such queries.
const assessmentDetails = await Entity.assessmentTest.findOne({
where: { id: assessmentId, status: 1 },
attributes: [
'id',
'sectionId',
'assessmentDate',
'assessmentTitle',
'totalPoints',
],
include: [
{
association: 'assessmentTestDetails',
where: { status: 1 },
attributes: ['marksObtained', 'percentage', 'testStatus'],
required: true,
order: [['marksObtained', 'ASC']],
include: [
{
association: 'student',
where: { status: 1 },
attributes: ['studentName'],
required: true,
},
],
},
],
I have many to many association like this following model:
const Movie = sequelize.define('Movie', { name: DataTypes.STRING });
const Actor = sequelize.define('Actor', { name: DataTypes.STRING });
const ActorMovies = sequelize.define('ActorMovies', {
MovieId: {
type: DataTypes.INTEGER,
references: {
model: Movie,
key: 'id'
}
},
ActorId: {
type: DataTypes.INTEGER,
references: {
model: Actor,
key: 'id'
}
}
});
Movie.belongsToMany(Actor, { through: ActorMovies });
Actor.belongsToMany(Movie, { through: ActorMovies });
And I succsessfully create Movie when create an Actor record with this following code:
Actor.create({
name: 'Jhony',
movies: [
{ name: 'Movie 1'}, // it will generate Movie with ID 1
{ name: 'Movie 2'} // it will generate Movie with ID 2
]
}, {
include: [ Movie ]
})
but my question how can I attach multiple existing Movie record when creating an Actor?
I already try:
Actor.create({
name: 'Edward',
movieIds: [1, 2]
}, {
include: [ Movie ]
})
and:
Actor.create({
name: 'Edward',
movies: [{id: 1}, {id: 2}]
}, {
include: [ Movie ]
})
But stil didn't work. Anyone can help me, please. Thanks in advance
You can't link existing movies to a new actor while creating it. You need to call setMovies of the new actor model instance:
const actor = await Actor.create({
name: 'Edward',
})
await actor.setMovies([1, 2])
Also, please pay attention that if you execute more than one query that changes something in DB it would be much more reliable to use transactions to turn all this queries into one atomic operation.
I'm trying to perform the following query using Sequelize:
db.Post.findAll({
include: [
{
model: db.User,
as: 'Boosters',
where: {id: {[Op.in]: a_set_of_ids }}
},
{
model: db.Assessment,
as: 'PostAssessments',
where: {UserId: {[Op.in]: another_set_of_ids}}
}
],
attributes: [[db.sequelize.fn('AVG', db.sequelize.col('Assessments.rating')), 'average']],
where: {
average: 1
},
group: ['id'],
limit: 20
})
But I run to this error: "ER_BAD_FIELD_ERROR". Unknown column 'Assessments.rating' in 'field list', although I do have table "Assessments" in the database and "rating" is a column in that table.
My Post model looks like this:
const Post = sequelize.define('Post', {
title: DataTypes.TEXT('long'),
description: DataTypes.TEXT('long'),
body: DataTypes.TEXT('long')
}, {
timestamps: false
});
Post.associate = function (models) {
models.Post.belongsToMany(models.User, {as: 'Boosters', through: 'UserPostBoosts' });
models.Post.hasMany(models.Assessment, {as: 'PostAssessments'});
};
What am I doing wrong?
It seems like this problem surfaces when we have a limit in a find query where associated models are included (the above error doesn't show up when we drop the limit from the query). To solve that, we can pass an option subQuery: false to the find. (https://github.com/sequelize/sequelize/issues/4146)
This is the correct query in case anyone comes across the same problem:
db.Post.findAll({
subQuery: false,
include: [
{
model: db.User,
as: 'Boosters',
where: {id: {[Op.in]: a_set_of_ids }}
}
,{
model: db.Assessment,
as: 'PostAssessments',
where: {UserId: {[Op.in]: another_set_of_ids}}
}
],
having: db.sequelize.where(db.sequelize.fn('AVG', db.sequelize.col('PostAssessments.rating')), {
[Op.eq]: 1,
}),
limit: 20,
offset: 2,
group: ['Post.id', 'Boosters.id', 'PostAssessments.id']
})
Error is with this one :
models.sequelize.col('Assessments.rating'))
Change it to
models.sequelize.col('PostAssessments.rating')) // or post_assessments.rating
Reason : You are using the alias for include as: 'PostAssessments',.
I have these two models: User and Conversation
User = sequelize.define('user', {
name: Sequelize.STRING
});
Conversation = sequelize.define('conversation', {
name: Sequelize.STRING
});
User.belongsToMany(Conversation, { through: 'user_conversation' });
Conversation.belongsToMany(User, { through: 'user_conversation' });
User and Conversation have a many to many relationship.
What I am trying to do is get all conversations that have userA and userB, and NO one else.
I have tried these two methods:
Conversation.findAll({
include: [{
model: User,
where: { id: { Op.and: [ userA.id, userB.id ] }
}]
});
This doesn't return anything, which makes sense. Id can't be A and B at the same time.
Conversation.findAll({
include: [{
model: User,
where: { id: { Op.or: [ userA.id, userB.id ] }
}]
});
This returns any conversation that users A and B are participating in.
How can I find any conversation where ONLY users A and B are involved? Can I somehow count the includes?
I am trying to querying a join table using sequelize:
Here is the model:
db.client.belongsToMany(db.user, {
through: db.clientUser,
onDelete: 'cascade',
});
db.user.belongsToMany(db.client, {
through: db.clientUser,
});
and this is what I am trying to do:
db.user.findAll({
where: {
group_id: 1,
},
include: [{
model: db.clientUser,
where: {
is_manager: 1,
}
}],
raw: true,
})
However I get the following error: client_user is not associated to user!
Any idea what could be the cause of this issue?
You declared a relationship between client from user through clientUser. Although pedantic, its complaint is technically correct: there is no explicitly declared relationship declared between client and clientUser. Nor should there be: your belongsToMany relationship should take care of that. Your query can be adjusted to work with this relationship.
Note: I don't know what tables group_id and is_manager are found in. They may need to be shuffled around.
db.user.findAll({
where: {
group_id: 1,
},
include: [{
model: db.client,
through: {
where: {
is_manager: 1, // Assuming clientUser.is_manager?
},
}],
raw: true,
})