问题
I have two models Contact and Thread with a many to many relationship represented across a join table ThreadContacts.
I need to write a query to find a Thread which has associations with an exact list of Contacts. For example, I might have a list of contact_id's
[1,2,3,4], and I need to find a Thread that is associated with these exact 4 contacts.
I have tried including Contact on a findAll query:
Thread.findOne({
include: [{
model: Contact,
where: { id: $in: [1, 2, 3, 4] },
}],
})
Of course this doesn't work because it'll return a thread that has a ThreadContact with any of the 4 ids.
I need something like this:
Thread.findAll({
include: contactIds.map(id => ({
model: Contact,
where: { id },
}),
})
However this also doesn't work because it is including duplicates of the same model.
What are my options here? I'm having a difficult time finding a solution for this.
回答1:
When writing more complicated join queries in sequelize, I usually end up using the raw query interface. It looks a bit complicated, but hopefully it makes sense:
- Select the Threads and join with the ThreadContact table
- Group by
Thread.id - Aggregate the group using array_agg on the contact ids. So we now have an array of all associated contacts for each thread.
- Then filter to where the aggregated array 'contains' (as represented by
@>) your inputted filter. See postgres array functions.
The result will be all Threads which are associated with at least those 4 contacts.
sequelize.query(`
SELECT Thread.*
FROM Thread
INNER JOIN ThreadContact
ON Thread.id = ThreadContact.threadId
GROUP BY Thread.id
HAVING array_agg(ThreadContact.contactId) @> ARRAY[:contactIds];
`, {
model: Thread,
mapToModel: true,
type: sequelize.QueryTypes.SELECT,
replacements: {contactIds: [1, 2, 3, 4]},
});
Also note that the column names may be incorrect from how your model is defined, I just made some assumptions on how they would look.
来源:https://stackoverflow.com/questions/41883695/sequelize-query-same-join-table-with-different-conditions