Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sequelize: Query same join table with different conditions

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.

like image 340
Ryan McClure Avatar asked Nov 01 '25 06:11

Ryan McClure


1 Answers

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.

like image 112
Sanketh Katta Avatar answered Nov 03 '25 21:11

Sanketh Katta



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!