מחק את כל המשתמשים שאינם בקבוצה ספציפית

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

nathank sought to delete all users not belonging to a specific group during a Discourse-to-Discourse migration, initially encountering issues with a Rails console command that accidentally deleted all users. After experimenting, they devised a workaround using the UI and Rails code, later refining the process by using a Data Explorer query to identify unwanted users and bulk-adding them to a temporary group named “unwanted” nathank. They emphasized using UserDestroyer instead of destroy to avoid orphaned database records and shared a script to safely delete users — first demoting them from admin/moderator roles, then destroying them with UserDestroyer.new(Discourse.system_user).destroy(u, delete_posts: true). The process, while functional, was slow — taking about two hours for 6,000 users. Key takeaways: always use UserDestroyer for clean deletions, and consider pre-filtering users via SQL queries for large-scale operations.

As part of a Discourse to Discourse migration / merger I’m trying to delete all of the users that are not in a specific group.

I tried this in the rails console:
User.joins(:group_users).where.not(group_users:{group_id:135}).destroy_all

Unfortunately, this deleted all users, which was a bit of a pain!

I have found a cumbersome way to do it using the UI and some ugly rails code, but is there an easy way to do this? I’ve probably just stuffed up the syntax.

Here is what I’ve tried, after painfully making a mega group of those to be deleted (about 6000) via the GUI:

rails c
 target_group = Group.find_by_name("nz-not")
 users = User.joins(:group_users).where(group_users:{group_id: target_group.id})
 users.each do |u|
 u.destroy
 end
exit

Also, what is the difference between using destroy and UserDestroyer? Should I be using the latter?

Answering my own question, having learned a few lessons.

  1. Yes, use UserDestroyer or your database will be littered with orphaned records.
  2. You might need to be clever about how you gather your unwanted users. I used this Data Explorer query to get a list of them, which I then bulk added them to a group called unwanted
WITH included_users AS (
SELECT
gu.user_id
FROM group_users gu
JOIN groups g
ON g.id = gu.group_id
WHERE g.name = :included_group
),

excluded_users AS (
SELECT
gu.user_id
FROM group_users gu
JOIN groups g
ON g.id = gu.group_id
WHERE g.name = :excluded_group
)

SELECT 
     u.id AS user_id, u.username
FROM users as u
WHERE u.id in (SELECT user_id FROM included_users)
AND u.id NOT IN (SELECT user_id FROM excluded_users)
GROUP by u.id

How to destroy a lot of users:

Enter the Discourse app (./launcher enter app, etc) and run these:

rails c
 target_group = Group.find_by_name("unwanted")
 users = User.joins(:group_users).where(group_users:{group_id: target_group.id})
 users.each do |u|
  u.admin = false
  u.moderator = false
  u.save
  UserDestroyer.new(Discourse.system_user).destroy(u, delete_posts: true)
 end
Exit

It isn’t fast. For 6000 users it took 2 hours.