使用需要多个值的子查询进行查询

时间:2020-03-20 07:03:03

标签: sql postgresql count typeorm

我真的想不出标题,所以让我解释一下这个问题:

问题::我想返回一个帖子数组,每个帖子都包含一个赞计数。点赞次数是针对特定帖子的,但适用于所有喜欢该帖子的用户

例如:

const posts = [
  {
    post_id: 1,
    like_count: 100
  },
  {
    post_id: 2,
    like_count: 50
  }
]

现在,按照我当前的解决方案,我认为这是不可能的,但是到目前为止,这是我所拥有的。

我的查询当前看起来像这样(由TypeORM生产):

SELECT
   "p"."uid" AS "p_uid",
   "p"."created_at" AS "post_created_at",
   "l"."uid" AS "like_uid",
   "l"."post_liked" AS "post_liked",
   "ph"."path" AS "path",
   "ph"."title" AS "photo_title",
   "u"."name" AS "post_author",
   (
      SELECT
         COUNT(like_id) AS "like_count" 
      FROM
         "likes" "l" 
         INNER JOIN
            "posts" "p" 
            ON "p"."post_id" = "l"."post_id" 
      WHERE
         "l"."post_liked" = true 
         AND l.post_id = $1
   )
   AS "like_count" 
FROM
   "posts" "p" 
   LEFT JOIN
      "likes" "l" 
      ON "l"."post_id" = "p"."post_id" 
   INNER JOIN
      "photos" "ph" 
      ON "ph"."photo_id" = "p"."photo_id" 
   INNER JOIN
      "users" "u" 
      ON "u"."user_id" = "p"."user_id"

$1应该位于post.post_id的位置(但是为了进行测试,我将第一条帖子的ID粘贴在其中),假设我已经准备好将一个post_id数组放置在其中。 / p>

我的TypeORM查询看起来像这样

  async findAll(): Promise<Post[]> {
    return await getRepository(Post)
    .createQueryBuilder('p')
    .select(['p.uid'])
    .addSelect(subQuery => 
      subQuery
        .select('COUNT(like_id)', 'like_count')
        .from(Like, 'l')
        .innerJoin('l.post', 'p')
        .where('l.post_liked = true AND l.post_id = :post_id', {post_id: 'a16f0c3e-5aa0-4cf8-82da-dfe27d3f991a'}), 'like_count'
    )
    .addSelect('p.created_at', 'post_created_at')
    .addSelect('u.name', 'post_author')
    .addSelect('l.uid', 'like_uid')
    .addSelect('l.post_liked', 'post_liked')
    .addSelect('ph.title', 'photo_title')
    .addSelect('ph.path', 'path')
    .leftJoin('p.likes', 'l')
    .innerJoin('p.photo', 'ph')
    .innerJoin('p.user', 'u')
    .getRawMany()
  }

我为什么要这样做?我要避免的是对页面上的每个帖子都调用count,以返回每个帖子的点赞次数。我以为可以以某种方式在子查询中执行此操作,但是现在我不确定是否可能。

有人可以建议一种更有效的方式来做这样的事情吗?还是这种方法完全错误?

1 个答案:

答案 0 :(得分:1)

我发现使用ORM太糟糕了,无法为此提供帮助。但是查询本身有缺陷:

  1. 您希望每条帖子排成一行,但是您正在加入likes,因此每条帖子都排成一行并喜欢。
  2. 您的子查询与您的主查询无关。相反,它应该与主要查询的帖子有关。

更正的查询:

SELECT
   p.uid,
   p.created_at,
   ph.path AS photo_path,
   ph.title AS photo_title,
   u.name AS post_author,
   (
      SELECT COUNT(*)
      FROM likes l 
      WHERE l.post_id = p.post_id
      AND l.post_liked = true 
   ) AS like_count 
FROM posts p 
JOIN photos ph ON ph.photo_id = p.photo_id 
JOIN users u ON u.user_id = p.user_id
ORDER BY p.uid;

我想您很容易将其转换为TypeORM。顺便说一句,计数每个帖子没有错。甚至有必要获得想要的结果。

还可以使用FROM将子查询移到GROUP BY l.post_id子句中。照原样,您将获得所有帖子,无论他们是否喜欢。通过将子查询移至FROM子句,您可以在INNER JOINLEFT OUTER JOIN之间进行选择。

查询将从以下索引中受益:

CREATE INDEX idx ON likes (post_id, post_liked);

如果查询似乎太慢,请提供此索引。