简体   繁体   中英

Find instances associated with multiple (all) instances from other model in Sequelize

Simplified Sequelize model example:

Post.belongsToMany(Tag)
Tag.belongsToMany(Post)

How do I findAll Posts that is associated with ALL of a set of tags?

Example dataset:

post
{ id: 1 }
{ id: 2 }

tag
{ id: 10 }
{ id: 11 }

post_tag
{ post_id: 1, tag_id: 10 }
{ post_id: 2, tag_id: 10 }
{ post_id: 2, tag_id: 11 }

So if the tags in question is 10 and 11 , the query should return Post 2 since it is associated with both tags, but not Post 1 since it is not associated with all the tags. (the number of tags could of course be more than two)

There may be a way to construct this request in one Sequelize findAll request, but I had to drop down to raw SQL to accomplish your task. Here are two approaches:

1. Get the post IDs and query Post.findAll with the results

Find post_ids that contain all tags

const postIds = await db.query(`
  SELECT post_id FROM (
    SELECT post_id, COUNT(*) AS counter
    FROM post_tag
    GROUP BY post_id
  ) AS tbl
  WHERE counter = (SELECT count(*) as COUNT from tags);;
`, {type: db.QueryTypes.SELECT})

Find posts that are present in the postIds array

const posts = await Post.findAll({
  where: {
    id: {
      $in: postIds.map(x => x.post_id)
    }
  }
});

2. Get posts in one SQL statement

const posts = await db.query(`
  SELECT *
  FROM posts
  WHERE id IN (
    SELECT post_id FROM (
      SELECT post_id, COUNT(*) AS counter
      FROM post_tag
      GROUP BY post_id
    ) AS tbl
    WHERE counter = (SELECT count(*) as COUNT from tags)
  )
`, {type: db.QueryTypes.SELECT});

(fwiw, I added both approaches because I prefer less raw SQL in application code)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM