Delete all users not in a specific group

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.

1 Like