简体   繁体   中英

Get instances where count of relationship is zero with Sequelize

Below is the syntax to count the relationship on a model via Sequelize

    const files = await db.File.findAll({
      attributes: {
        include: [
          [Sequelize.fn('COUNT', 'Tags.id'), 'tagCount']
        ]
      },
      include: [
        {
          model: db.Tag,
          as: 'tags',
          attributes: [],
          duplicate: false
        }
      ],
      group: 'File.id',
      order: [
        [Sequelize.literal('`tagCount`'), 'DESC']
      ]
    })

What do I require to make this code return only Files that has zero tags associated to them?

Edit

As per answer provided by @Soham, it does achieve the intended result but cannot be paginated. Generated query is:

SELECT `File`.`id`,
`File`.`originalId`,
`File`.`signature`,
`File`.`referrer_url`,
`File`.`preview_url`,
`File`.`preview_extension`,
`File`.`original_url`,
`File`.`original_extension`,
`File`.`provider`,
`File`.`previewedAt`,
`File`.`viewedAt`,
`File`.`blacklistedAt`,
`File`.`queuedAt`,
`File`.`startedAt`,
`File`.`downloadedAt`,
`File`.`createdAt`,
`File`.`updatedAt`,
COUNT(`tags`.`id`) AS `tagCount`,
`tags->FileTags`.`createdAt` AS `tags.FileTags.createdAt`,
`tags->FileTags`.`updatedAt` AS `tags.FileTags.updatedAt`,
`tags->FileTags`.`fileId` AS `tags.FileTags.fileId`,
`tags->FileTags`.`tagId` AS `tags.FileTags.tagId` 
FROM `Files` AS `File` 
LEFT OUTER JOIN `FileTags` AS `tags->FileTags` 
ON `File`.`id` = `tags->FileTags`.`fileId` 
LEFT OUTER JOIN `Tags` AS `tags` 
ON `tags`.`id` = `tags->FileTags`.`tagId` 
GROUP BY `File`.`id` 
HAVING `tagCount` = 0 
ORDER BY `tagCount` DESC;

When I add offset and limit to the query as per below

    return super.findAll({
      offset: 0,
      limit: 24,
      attributes: {
        include: [
          [Sequelize.literal('COUNT(`tags`.`id`)'), 'tagCount']
        ]
      },
      include: [
        {
          model: db.Tag,
          as: 'tags',
          attributes: [],
          duplicate: false
        }
      ],
      group: 'File.id',
      order: [
        [Sequelize.literal('`tagCount`'), 'DESC']
      ],
      having: { tagCount: 0 }
    })

and this outputs the following

SELECT `File`.*,
 `tags->FileTags`.`createdAt` AS `tags.FileTags.createdAt`,
 `tags->FileTags`.`updatedAt` AS `tags.FileTags.updatedAt`,
 `tags->FileTags`.`fileId` AS `tags.FileTags.fileId`,
 `tags->FileTags`.`tagId` AS `tags.FileTags.tagId` 
 FROM (SELECT `File`.`id`,
 `File`.`originalId`,
 `File`.`signature`,
 `File`.`referrer_url`,
 `File`.`preview_url`,
 `File`.`preview_extension`,
 `File`.`original_url`,
 `File`.`original_extension`,
 `File`.`provider`,
 `File`.`previewedAt`,
 `File`.`viewedAt`,
 `File`.`blacklistedAt`,
 `File`.`queuedAt`,
 `File`.`startedAt`,
 `File`.`downloadedAt`,
 `File`.`createdAt`,
 `File`.`updatedAt`,
 COUNT(`tags`.`id`) AS `tagCount` 
 FROM `Files` AS `File` 
 GROUP BY `File`.`id` 
 HAVING `tagCount` = 0 
 ORDER BY `tagCount` DESC LIMIT 0,
 24) AS `File` 
 LEFT OUTER JOIN `FileTags` AS `tags->FileTags` 
 ON `File`.`id` = `tags->FileTags`.`fileId` 
 LEFT OUTER JOIN `Tags` AS `tags` 
 ON `tags`.`id` = `tags->FileTags`.`tagId` 
 ORDER BY `tagCount` DESC;

To filter records having tag count zero you need to use having clause as follows -

const files = await db.File.findAll({
  attributes: {
    include: [
      [Sequelize.fn('COUNT', 'Tags.id'), 'tagCount']
    ]
  },
  include: [
    {
      model: db.Tag,
      as: 'tags',
      attributes: [],
      duplicate: false
    }
  ],
  group: 'File.id',
  order: [
    [Sequelize.literal('`tagCount`'), 'DESC']
  ],
  having: { tagCount : 0 },
  subQuery: false
})

i cant add a comment on an answer, so please see my answer as a comment on the upvoted one.

Sequelize.fn('COUNT', 'Tags.id') 

should be

Sequelize.fn('COUNT', Sequelize.col('Tags.id'))

if 'Tags.id' is not wrapped with Sequelize.col() the generated sql looks like: COUNT('Tags.id').

working example:

const files = await db.File.findAll({
    attributes: {
    include: [
      [Sequelize.fn('COUNT', Sequelize.col('Tags.id')), 'tagCount']
    ]
  },
  include: [
    {
      model: db.Tag,
      as: 'tags',
      attributes: [],
      duplicate: false
    }
  ],
  group: 'File.id',
  order: [
    [Sequelize.literal('`tagCount`'), 'DESC']
  ],
  having: { tagCount : 0 },
  subQuery: false
})

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