Bulk remove users

סיכום מבוסס בינה מלאכותית

Users are discussing how to bulk remove inactive users in Discourse after importing data from phpBB3. yavuz initially imported 4,000 users with no posts and sought a way to delete them. zogstrip suggested using Rails console with User.where(post_count: 0).destroy_all, but this failed because post_count is now stored in the user_stats table. zogstrip corrected the query to User.joins(:user_stat).where("user_stats.post_count = 0").destroy_all, which yavuz confirmed works. jomaxro extended the query to also filter users inactive for over a year, which zogstrip approved. Queth asked how to delete all non-admin users before final import to prevent accidental emails, and leonardo recommended using UserDestroyer for safer, cleaner deletions: destroyer = UserDestroyer.new(Discourse.system_user); User.joins(:user_stat).where("user_stats.post_count = 0").each { |u| destroyer.destroy(u) }. Users are advised to always backup before running destructive queries.

I have imported my old data from phpBB3 which went smooth. But I made a mistake by not first cleaning up the old inactive users and still importing them. I now have around 4000 users with no posts I wish to remove.

What is the best way to bulk remove users?

If you really don’t care about these users, then I would do this

  1. make a backup (better safe than sorry)
  2. ssh into your server and type
cd /var/discourse
./launcher enter app
rails c
User.where(post_count: 0).destroy_all

These instructions produce the following error:
[1] pry(main)> User.where(post_count: 0).destroy_all ActiveRecord::StatementInvalid: PG::UndefinedColumn: ERROR: column users.post_count does not exist LINE 1: SELECT "users".* FROM "users" WHERE "users"."post_count" = 0 ^ : SELECT "users".* FROM "users" WHERE "users"."post_count" = 0 from /var/www/discourse/vendor/bundle/ruby/2.3.0/gems/rack-mini-profiler-0.10.1/lib/patches/db/pg.rb:90:in `exec'

This is not really documented I think but if it is please point me in the right direction?

“post count” != “post_count” ??

My bad, the post_count property was moved to another table for optimization reasons.

Here’s the updated query

User.joins(:user_stat).where("user_stats.post_count = 0").destroy_all

Thank you, the updated query works!

One of my sites uses SSO and we’re looking to remove users that have never posted and haven’t been seen in a year (to avoid killing users who are just quiet). Is this query valid in the rails console?

User.joins(:user_stat).where("user_stats.post_count = 0 AND previous_visit_at <= '2016-05-20'::timestamp").destroy_all

It looks good to me.

I have the same issue, but with users I need to remove before doing the final import. I have been working on creating a base setup with all settings/themes/whatever before doing the import - now (after a lot of work) I discover I had done this on a partial import that had imported 4000 users already.

I wish to delete those so nobody will accidentally get any emails of digests or whatever (when I forget to change those settings).

How do I adapt that query so only the admin user will remain ?
There are 4000 or so in the active userlist
and 30 or so in the suspended users list.

thank you in advance :slight_smile:

Note: nowadays there is a specific class for destroying Users and associated records cleanly: UserDestroyer.

So instead of this:

This should be done:

destroyer = UserDestroyer.new(Discourse.system_user)
User.joins(:user_stat).where("user_stats.post_count = 0").each { |u| destroyer.destroy(u) }