Concepts
Saving data
Keep coins, levels, warnings and settings after a command ends.
Variables in your code are gone when the command ends. To keep something, save it. There are three ways:
| Way | Good for | Kept after restart |
|---|---|---|
| Server and member variables | One value: a counter, a setting, a user's coins | Yes |
| Mongo database | Lists and records: inventories, warnings, leaderboards | Yes |
| Temp variables | Short-lived values | No |
Start with member variables for simple things. Move to Mongo when you need lists, many fields per user, or sorting.
Server variables#
One value for the whole server.
count = int(server_var("counter", 0))
update_server_var("counter", count + 1)
set_content(f"This command was used {count + 1} times.")server_var(name, default)reads a value. Givesdefaultwhen it was never saved.update_server_var(name, value)saves a value.
You can see and edit saved values on the dashboard under Variables.
Member variables#
One value per member. Without member=, it is the person who ran the command.
coins = int(member_var("coins", 0))
update_member_var("coins", coins + 100)
set_content(f"You now have {coins + 100} coins.")For someone else, pass member=:
their_coins = int(member_var("coins", 0, member=target))Values come back as text
Saved values are stored as text. member_var("coins") gives "100", not 100. Wrap it in int(...) before doing sums.
Mongo databases#
A Mongo database stores records. A record is a set of named fields, like a row:
{"user_id": 123, "coins": 500, "items": ["sword", "shield"]}Open one with SlashMongo(database, collection). Pick any names. Each server gets its own private copy.
db = SlashMongo("economy", "wallets")
wallet = await db.find_one({"user_id": user.id})
coins = wallet["coins"] if wallet else 0
await db.update_one(
{"user_id": user.id},
{"$set": {"coins": coins + 100}},
upsert=True,
)upsert=True makes the record when it does not exist yet.
Common actions#
| Code | What it does |
|---|---|
await db.insert_one(record) | Add one record. |
await db.find_one(filter) | Get the first match, or None. |
await db.find(filter) | Get all matches, as a list. |
await db.update_one(filter, changes) | Change the first match. |
await db.delete_one(filter) | Delete the first match. |
await db.count(filter) | Count matches. |
Write await in front of every Mongo call.
Top 10 leaderboard#
db = SlashMongo("economy", "wallets")
top = await db.aggregate([
{"$sort": {"coins": -1}},
{"$limit": 10},
])
lines = [f"<@{w['user_id']}>: {w['coins']}" for w in top]
set_content(listify(lines, prefix="number"))You can browse your data on the dashboard under Mongo Databases.
Databases#
Databases (under Variables) are tables you set up on the dashboard first, with fixed columns. Open one by its ID:
db = await load_database("my_table_id")
rows = db.find(where={"user_id": str(user.id)})
await db.insert({"user_id": str(user.id), "note": "hello"})Use these when you want to manage the rows by hand on the dashboard. For data that code writes, Mongo is easier.
Temp variables#
Kept in memory only. They vanish when the bot restarts.
set_temp_var("last_winner", user.id)
winner = temp_var("last_winner")Use them for short-lived values where losing them does not matter.
Locks#
Two people can run a command at the same time. When both change the same record, one change can be lost. Wrap the change in a lock:
acquire_lock(f"wallet-{user.id}", error="Slow down, try again.")
# ... read, change, save ...
release_lock(f"wallet-{user.id}")Always release the lock
A lock is not released when the command ends. If your code stops with an error between the two lines, the lock stays on and the command keeps saying "Slow down". Keep the code between them short and safe, or release the lock before any set_error.
Full list: Storage reference.