Is it possible to see who voted in polls?

I just tested out polls for the first time in a while, and it works quite well and I like it.

But I would like to have an open poll so we can see who voted for which option. Is this possible? Is there any way to see who voted for what?

You can run the following query to get a list of users who voted and their selected poll options.
Please choose the appropriate query for your Discourse version.

Query for Discourse v2.2.0.beta5 and newer

-- [params]
-- post_id :post_id
-- text :poll_name = poll

SELECT u.id AS user_id, u.username, v.poll_option_id AS option_id, o.html AS option_html
FROM polls p
       JOIN poll_votes v ON (p.id = v.poll_id)
       JOIN poll_options o ON (o.id = v.poll_option_id)
       JOIN users u ON (v.user_id = u.id)
WHERE p.post_id = :post_id AND p.name = :poll_name
ORDER BY u.username, v.poll_option_id

Query for older versions of Discourse up to v2.2.0.beta4

-- [params]
-- post_id :post_id
-- text :poll_name = poll

SELECT votes.user_id, users.username, votes.option_id, options.html AS option_html
FROM (
  SELECT value1 ->> 'id' AS id,
    value1 ->> 'html' AS html
  FROM (
    SELECT json_array_elements(value :: JSON -> :poll_name -> 'options') AS value1
    FROM post_custom_fields
    WHERE post_id = :post_id AND name = 'polls' AND value :: JSON -> :poll_name ->> 'name' = :poll_name
  ) option_values
) options
       JOIN (
  SELECT key :: INTEGER AS user_id,
    trim(json_array_elements(value :: JSON -> :poll_name) :: TEXT, '"') AS option_id
  FROM json_each((
    SELECT value :: JSON
    FROM post_custom_fields
    WHERE post_id = :post_id AND name LIKE 'polls-votes'
  ))
) votes ON (options.id = votes.option_id)
       JOIN users ON (votes.user_id = users.id)
ORDER BY users.username, votes.option_id

How to find post_id

You can use the following query if you need to find the right post_id.

-- [params]
-- topic_id :topic_id
-- int :post_number = 1

SELECT id
FROM posts
WHERE topic_id = :topic_id AND post_number = :post_number

it works! thanks so much. :fireworks:

is there a query for quickly identifying the post ID containing polls? I used the .json URL method but it was surprisingly cumbersome to find the right post within it.

Default values are specified like this:

I updated the query. It’s now a lot simpler. :slight_smile:

Можно ли отфильтровать результаты по возрасту аккаунта?

Например, если аккаунту меньше 60 дней, он не отображается в результатах? Или, возможно, есть способ создать опрос, который ограничивает голосование в зависимости от возраста аккаунта?

Мы пытаемся предотвратить возможную накрутку голосов с помощью недавно созданных аккаунтов перед важным голосованием.

Это очень интересный случай использования. Я считаю, что нам стоит добавить возможность запрещать пользователям уровня TL0 голосовать в опросах, @zogstrip!

Есть ли параметр, который можно добавить к строке поиска от @gerhard, чтобы в запросе не отображались пользователи с уровнем доверия или возрастом аккаунта ниже определённого?

Даже если бы мне пришлось вручную подсчитывать голоса на основе результатов, это было бы быстрее, чем вручную проверять возраст каждого аккаунта и их голоса.

Вот запрос для установки минимального уровня доверия пользователей.

-- [params]
-- post_id :post_id
-- text :poll_name = poll
-- integer :min_trust_level

SELECT u.id AS user_id, u.username, v.poll_option_id AS option_id, o.html AS option_html
FROM polls p
       JOIN poll_votes v ON (p.id = v.poll_id)
       JOIN poll_options o ON (o.id = v.poll_option_id)
       JOIN users u ON (v.user_id = u.id)
WHERE p.post_id = :post_id AND p.name = :poll_name
  AND u.trust_level >= :min_trust_level
ORDER BY u.username, v.poll_option_id

А вот запрос для отображения только тех пользователей, которые зарегистрировались определённое количество дней назад.

-- [params]
-- post_id :post_id
-- text :poll_name = poll
-- integer :days_ago = 30

SELECT u.id AS user_id, u.username, v.poll_option_id AS option_id, o.html AS option_html
FROM polls p
       JOIN poll_votes v ON (p.id = v.poll_id)
       JOIN poll_options o ON (o.id = v.poll_option_id)
       JOIN users u ON (v.user_id = u.id)
WHERE p.post_id = :post_id AND p.name = :poll_name
  AND u.created_at < NOW() - INTERVAL ':days_ago days' 
ORDER BY u.username, v.poll_option_id

Супер :heart_eyes: @gerhard, спасибо!

Обратите внимание, что этот запрос теперь включен в стандартные запросы Data Explorer, которые устанавливаются автоматически, поэтому вам не нужно вводить этот код самостоятельно!

Другой способ найти ID поста, особенно если это первый пост, — посмотреть файл <topic_url>.json (например, Is it possible to see who voted in polls?). В начале этого JSON-файла ID поста найти довольно легко.

@nbianca Можешь добавить в свой список новый параметр опроса min_trust_level, который позволит создателям опросов ограничивать возможность голосования в зависимости от уровня доверия пользователей?

Эта опция должна быть доступна в интерфейсе конструктора опросов, а также должно быть отображено понятное сообщение, объясняющее, почему некоторые пользователи не могут голосовать в данном опросе.

Вам даже не нужно искать post_id, так как теперь для сотрудников доступна кнопка экспорта в опросах.

Это уже реализовано, но немного иначе, чем было запрошено. Опросы принимают параметр groups, а не min_trust_level. Параметр groups принимает список названий групп, разделённых запятыми (например, trust_level_2,staff, чтобы разрешить голосование пользователям с уровнем доверия 2 и выше, а также всем сотрудникам).

Извините, но для меня это слишком запутанно. Не могли бы вы разобрать это по шагам?