Skip to content

DaisyVotes — Database Access

Building a vote page for your website, or a Discord bot that shows top voters? DaisyVotes’ tables are plain SQL and you are welcome to read them. This page is the contract: what the columns mean, and the queries that give the right answer.

Point your site at the same database the plugin uses. For a website integration you want MySQL or MariaDB, not the default SQLite — a SQLite file on the game server is not reachable from your web host. See Storage & Data for switching.

Create a separate, read-only database user for the website. It never needs to write, and a credential that lives in a web root should not be able to.

CREATE USER 'daisyvotes_web'@'%' IDENTIFIED BY 'a-long-random-password';
GRANT SELECT ON your_database.vote_players TO 'daisyvotes_web'@'%';
GRANT SELECT ON your_database.vote_events TO 'daisyvotes_web'@'%';

This catches everyone once. The columns are named exactly as the plugin’s fields are — totalVotes, not total_votes.

ColumnMeaning
uuidMinecraft UUID, with dashes. Primary key.
nameLast known username. Changes when the player renames.
totalVotesVotes of all time. Always safe to read.
dailyVotes weeklyVotes monthlyVotesVotes in that period — only valid alongside the matching key column below.
dailyKey weeklyKey monthlyKeyWhich period the counter beside it counted: 2026-08-10, 2026-W33, 2026-08.
currentStreak bestStreakConsecutive days voted.
votePoints lifetimeVotePointsShop currency: current balance, and total ever earned.
lastVoteAt firstVoteAtEpoch milliseconds, not seconds.
ColumnMeaning
idRandom UUID.
playerUuid playerNameWho voted.
siteId serviceNameWhich site, as configured and as the site announced itself.
receivedAtEpoch milliseconds. Indexed.

A player’s dailyVotes is only rolled over to zero when that player next votes. Somebody who last voted on Tuesday still carries Tuesday’s daily total on Friday. The column looks authoritative and is not.

The key column says which period the number belongs to. Match it against the current period and stale rows simply do not appear.

SELECT name, dailyVotes AS votes
FROM vote_players
WHERE dailyKey = ? AND dailyVotes > 0
ORDER BY dailyVotes DESC
LIMIT 10;

Bind the key as Y-m-d, e.g. 2026-08-10.

The keys are written by the Minecraft server, in whatever wheel.reset-zone is set to in config.yml (server means the game host’s own zone). If your web host is in a different zone, computing “today” locally puts the site out of step with the game for part of every day.

// PHP — note 'o' (ISO week-numbering year) and 'W' (ISO week), not 'Y' and 'W'.
$tz = new DateTimeZone('Europe/London'); // must match wheel.reset-zone
$now = new DateTime('now', $tz);
$dailyKey = $now->format('Y-m-d'); // 2026-08-10
$weeklyKey = $now->format('o') . '-W' . $now->format('W'); // 2026-W33
$monthlyKey = $now->format('Y-m'); // 2026-08

If you would rather not depend on the counters at all, aggregate vote_events. It is the ground truth, the window is explicit, and it cannot be stale — at the cost of a GROUP BY instead of an indexed sort.

SELECT playerName, COUNT(*) AS votes
FROM vote_events
WHERE receivedAt >= ? -- window start, epoch MILLIseconds
GROUP BY playerUuid, playerName
ORDER BY votes DESC
LIMIT 10;

Use this when you need a window the plugin does not track — “last 7 days”, “this season”, per-site totals. Use the counters for the standard daily/weekly/monthly boards; that is what they are indexed for.

  • Cache the result. A leaderboard does not need to be live to the second. A minute or two of caching removes essentially all load from the game server’s database.
  • UUIDs have dashes. Some avatar and profile APIs want them stripped.
  • A UUID that resolves to no Minecraft account is probably from before 2.6.0: a vote arriving while the player was offline used to get a UUID derived from their name. Those rows are real votes under the wrong identity. See Migrating.
  • Never write to these tables while the server is running. The plugin caches player rows in memory and will overwrite you.
  • vote_events grows forever. Nothing prunes it. It is indexed on receivedAt, so windowed queries stay fast, but do not SELECT * from it without a WHERE.
  • totalVotes and COUNT(vote_events) can disagree on a server that ran a version before 2.6.0, where two simultaneous votes could be credited once while both events were still recorded. From 2.6.0 they track each other.