批量永久删除已删除的帖子?

If I am not mistaken there is a field called deleted_at

If it is deleted, then there should be a date time Stamp.

If it is not deleted then is null

Maybe look for the entry that is <> Null and delete

1 个赞

Thanks Gav, but the ones that I am targeting aren’t marked as deleted. Rather, their Topic has been deleted and then destroy_all’d.

2 个赞

I was playing around with this and i notice that part of your query was not returning the response you need.

SELECT topic_id from posts does not return an integer, but it returned a string

image

This might be the cause that your db still contains orphaned posts.

2 个赞

我认为您看到的是 Data Explorer 自动将整数转换为 URL,当标签为 topic_id 时,它会这样做。

当我在 Data Explorer 中运行此查询时,我尝试识别的所有帖子都被捕获(远超 5000 个):

SELECT id, topic_id
FROM posts
WHERE topic_id not in (select id from topics)
ORDER by id

我显然在 Rails 语法上做错了,因为我得到的是:

[1] pry(main)> Target = Post.where('topic_id not in (select id from topics)')
=> []

有人能告诉我我哪里做错了吗?

1 个赞

多亏了 @pfaffman,我使用以下方法识别了相关帖子:

Post.find_by_sql("select id from posts where topic_id not in (select id from topics)")

我得到了以下输出:

[1] pry(main)> Post.find_by_sql(“select id from posts where topic_id not in (select id from topics)”)
=> [#<Post:0x000055df30d4ee90 id: 150>,
#<Post:0x000055df2e538ff0 id: 51097>,
#<Post:0x000055df2e50ba28 id: 83>,
#<Post:0x000055df2e4ee8b0 id: 40636>,
#<Post:0x000055df2e4a92d8 id: 62562>,
#<Post:0x000055df2e4b7978 id: 13522>,
etc

但是,我不知道如何将 destroy_all 应用于此选择。

这可能有助于(对我自己而言):

有什么建议吗?

1 个赞

我认为这会起作用

posts=
Post.find_by_sql("select id from posts where topic_id not in (select id from topics)")


posts.destroy_all

或者你也可以在 find_by_sql 中添加 .destroy_all

2 个赞

我已经试过了。数据似乎被返回为一个数组,其中包含一些帖子标识符和 ID(参见 https://meta.discourse.org/t/delete-deleted-posts-permanently-in-bulk/203289/45)。

当我添加 .destroy_all 或使用你建议的 posts= 时,我收到的错误是:

[2] pry(main)> posts.destroy_all
NoMethodError: undefined method destroy_all' for #<Array:0x000055fe7bc7fc98> from (pry):3:in pry

1 个赞

哦。那么也许可以看看

 p=posts.first

是否是 post_id。如果是这样,那么你就可以

x=Post.find(p)
x.destroy

然后你可以循环遍历它们。

我认为你需要将你的查询包装在某个东西中,使其成为一个帖子的数组而不是 post ids。

1 个赞

谢谢 Jay。我得到的是:

[3] pry(main)> p=
[3] pry(main)* posts.first
=> #<Post:0x0000563a24cab908 id: 150>
[4] pry(main)> x=Post.find(p)
ArgumentError: You are passing an instance of ActiveRecord::Base to find. Please pass the id of the object by calling .id.
from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activerecord-6.1.4.1/lib/active_record/relation/finder_methods.rb:467:in `find_one’

现在,告诉我关于这些包装的东西。这太烦人了,因为我知道 @Sam 的这个 rails 命令应该可以工作,但我认为 Rails 已经和那时不一样了:

1 个赞

那做了什么?我无法想象 Rails 发生了变化。

1 个赞

这能得到你想删除的帖子吗?

1 个赞

我在网上搜索将 Active Record 数组转换为 Active Record Relation 时读到,Rails 3.x 和 Rails 4 之间的语法有所不同,但当时我没太理解。

我第一次运行它时,它似乎找到了一些帖子,并且我 duly destroy_all 了它们。但数量不多。现在一个也找不到,而当我在 Data Explorer 中运行 SQL 时,却能找到数千条。

这些是孤立的帖子,它们的 Topic 已经被 Destroy_all 了。

1 个赞

您可以使用 each{} 来迭代该数组的成员,单独调用 destroy 来删除每个帖子。

Post.find_by_sql(“select id from posts where topic_id not in (select id from topics)”).each { |p| p.destroy }
2 个赞

好吧,我试了一下。起初它不喜欢这样封装的 SQL 语法,也不喜欢这种语法:

Post.find_by_sql(“select id from posts where topic_id not in (select id from topics)”).each { |p| p.destroy_all }
SyntaxError: unexpected `in’, expecting ‘(’
…rom posts where topic_id not in (select id from topics)”)…
… ^~
SyntaxError: unexpected local variable or method, expecting end-of-input
…t in (select id from topics)”).each { |p| p.destroy_all }

所以我又尝试了一种笨拙的方法,把它分开:

posts=Post.find_by_sql("select id from posts where topic_id not in (select id from topics)")
posts.each do |p|
p.destroy
end

这似乎运行得还可以,但添加 p.destroy 会出现这个错误:

ActiveModel::MissingAttributeError: missing attribute: user_id
from /var/www/discourse/vendor/bundle/ruby/2.7.0/gems/activemodel-6.1.4.1/lib/active_model/attribute.rb:222:in `value’

我尝试了几种方法来解决这个问题,但最终放弃了。@sam,你能帮忙吗?

附注

我甚至尝试按照这个方法,通过 scuttle.io 将 SQL 转换为 AR:

Post.select([:id, :topic_id]).where(Topic.select(:id))

唉,我遇到了这个错误:

ArgumentError: Unsupported argument type: #Topic::ActiveRecord_Relation:0x000055c67a7131d0 (Topic::ActiveRecord_Relation)

3 个赞

当我从之前的消息中复制粘贴那部分时,引号似乎在某个地方被转换成了花引号,我猜那才是真正的错误。抱歉。

find_by_sql 被描述为返回一个具有 SQL 查询中指定值的对象,这可能意味着你得到的是一个 Post 对象,其中只有 id 属性被设置,而 user_id 和其他所有属性都丢失了。

... find_by_sql("select * ... 将会处理这个问题。可能有一个值的子集可以用来实现销毁,而不是选择所有值,但我不知道这个子集是什么。

所以整个代码是:(这次没有花引号……)

Post.find_by_sql("select * from posts where topic_id not in (select id from topics)").each { |p| p.destroy }
4 个赞

:partying_face: 赞美! :partying_face:

谢谢 Simon - 这个方法非常有效。孤立的帖子都消失了,我期待着在接下来的 24 小时左右我的上传量会大大减少。

稍后
果然减少了!从 3.5GB 降至 0.7GB。太棒了!!

7 个赞

太好了,很高兴听到这能帮到你。为了合并这些答案,你可以在 Rails 控制台中执行以下命令来销毁所有已删除超过 90 天的主题,如果主题超过 1000 个,则重复执行以销毁所有主题:

Topic.with_deleted.where(deleted_at: ...90.days.ago).limit(1000).destroy_all

完成上述操作后,可以使用以下命令销毁所有已孤立于已销毁主题的帖子:

Post.find_by_sql("select * from posts where topic_id not in (select id from topics)").each { |p| p.destroy }

值得注意的是,上述命令不会销毁已删除的帖子,只会销毁已删除的主题及其孤立的帖子。要同时销毁已删除的、超过 90 天的帖子,请使用以下命令,同样根据需要重复执行:

Post.with_deleted.where(deleted_at: ...90.days.ago).limit(1000).destroy_all

附言 顺便问一下,你是否尝试过不带 limit(1000)destroy_all 并遇到了问题,还是你根本没有尝试过不带限制的命令?

8 个赞

我尝试过不带限制的它,结果有点失控——但抱歉,我记不清具体细节了。

我们可以将你的帖子标记为解决方案,或者使用 OP 的内容吗?

image

3 个赞

没关系。如果你没试过,我会加个注释说这个限制可能不是必需的,但既然你遇到了问题,我就保持原样。

1 个赞

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.