ruby-on-rails 统计此类别和所有子类别中的所有帖子- ActiveRecord

zaqlnxep  于 2023-04-08  发布在  Ruby
关注(0)|答案(2)|浏览(132)

我的项目中有两个表:postspost_categoriesposts表中的每个帖子都有一个与post_categories.id相关的post_category_id作为fk,post_categories中的每个条目都有一个parent_id-自引用post_categories.id
在网站上,职位类别页面显示在每个类别的所有职位,但我需要它也计算在每个子类别的所有职位。
post_categories(0 =主菜单)

+-----+---------------+-----------+
| id  | title         | parent_id |
+-----+---------------+-----------+
| 1   | Machines      | 0         |
| 2   | Vehicles      | 1         |
| 3   | Industrial    | 1         |
| 4   | Road Cars     | 2         |
| 5   | Track Cars    | 2         |
+-----+---------------+-----------+

posts

+-----+--------+------------------+
| id  | title  | post_category_id |
+-----+--------+------------------+
| 1   | Rally  | 5                |
| 2   | F1     | 5                |
| 3   | Vans   | 4                |
| 4   | Trucks | 4                |
+-----+--------+------------------+

到目前为止,如果有一个类别没有直接在其下的任何帖子,它显示0个帖子,即使该类别包含2个类别,总共有50个帖子。
我花了很多时间在MySQL RECURSIVE函数上绕圈子,但没有用。它看起来很简单,但我找不到一个RECURSIVE查询的例子,它考虑了第二个表,并且不可能为多层编码,因为没有硬性限制可以有多少层。
为了澄清,然后,让我们假设我们在车辆菜单(post_category_id:2).我的查询应该:
1.统计post_category_id = 2的所有帖子(本例中无)。
1.统计所有post_category_id为IN(4,5)的帖子-因为post_category 4和5的parent_id都为2。
1.将这些数字相加,并给予包含帖子总数和类别数的两列,以便打印:Post Category Title (Contains 30 posts in 6 categories)
有人能提供一个递归的解决方案吗?

oaxa6hgo

oaxa6hgo1#

这可能不是最有效的方法,但它是有效的。递归CTE构建给定类别的所有后代的列表(从CTE中的第一个查询中删除WHERE子句以构建所有类别):

WITH RECURSIVE hierarchy (id, descendant, top_level_id) AS (
    SELECT id, FALSE, id
    FROM post_categories
    WHERE id = 2

    UNION ALL

    SELECT pc.id, TRUE, h.top_level_id
    FROM hierarchy h
    JOIN post_categories pc ON h.id = pc.parent_id
)
SELECT
    pc.*,
    SUM(descendant) AS num_categories,
    SUM((SELECT COUNT(*) FROM posts WHERE post_category_id = h.id)) AS num_posts
FROM post_categories pc
JOIN hierarchy h ON h.top_level_id = pc.id
WHERE pc.id = 2
GROUP BY pc.id;

对于您的问题中提供的示例数据,它输出:
| 身份证|标题|父ID|num_categories|员额数|
| --------------|--------------|--------------|--------------|--------------|
| 二|车辆|1|二|四|
如果对所有类别运行,则应预先聚合类别计数,因为它们将被多次要求:

WITH RECURSIVE hierarchy (id, descendant, top_level_id) AS (
    SELECT id, FALSE, id
    FROM post_categories

    UNION ALL

    SELECT pc.id, TRUE, h.top_level_id
    FROM hierarchy h
    JOIN post_categories pc ON h.id = pc.parent_id
),
cat_counts (id, cnt) AS (
    SELECT pc.id, COUNT(p.id)
    FROM post_categories pc
    LEFT JOIN posts p ON pc.id = p.post_category_id
    GROUP BY pc.id
)
SELECT pc.*, SUM(descendant) AS categories, SUM(cc.cnt) AS num_posts
FROM post_categories pc
JOIN hierarchy h ON h.top_level_id = pc.id
JOIN cat_counts cc ON h.id = cc.id
GROUP BY pc.id;

其输出:
| 身份证|标题|父ID|分类|员额数|
| --------------|--------------|--------------|--------------|--------------|
| 1|机器|空|四|四|
| 二|车辆|1|二|四|
| 三|工业领域|1|0|0|
| 四|公路汽车|二|0|二|
| 五|轨道汽车|二|0|二|
这里有一个db<>fiddle

mu0hgdu0

mu0hgdu02#

我有一对夫妇的问题以上,将有助于完善这个答案,如果它不是你正在寻找的。

def post_and_cat_count(title)
  
  lookup_category = PostCategory.find_by(title: title).id
  child_categories = PostCategory.where(parent_id: lookup_category)

  post_count = Post.where(post_category_id: lookup_category).count + 
  Post.where(post_category_id: child_categories).count

  {posts: post_count, categories: (child_categories.length + 1)}

end

display_counts = post_and_cat_count('Vehicles')
#=> {posts: 4, categories: 3}

puts "Post Category Vehicles (Contains #{display_counts[:posts]} posts in #{display_counts[:categories]} categories)
#=> 'Post Category Vehicles (Contains 4 posts in 3 categories)'

我想这就是你要找的?如果你需要更递归的东西,那么你需要扩展你的问题并给予一个递归的例子。我的意思是一个方法会调用自己并用return子句打破无限循环的情况。

相关问题