Search code examples
pythonmysqldiscordbotsnextcord

How to update a database using a loop?


I'm trying to get my bot to check the database every second, and if someone has 800 XP, to change their rank to 'Elite Genin'.

@bot.event
async def on_ready():
    print(f"Logged in as: {bot.user.name}")

    if not loop.is_running():
        loop.start()


@tasks.loop(seconds = 1)
async def loop(ctx):
    guild = ctx.guild.id
    table = "PEOPLE_" + str(guild)

    try:
        connection = mysql.connector.connect(
        host="localhost",
        port="3306",
        user="root",
        password="root",
        database="naruto_game"
        )
        cursor = connection.cursor()
    except mysql.connector.Error as error:
        print("Failed to find name: {}".format(error))
    finally:
        print(f"Logged in as: {bot.user.name}")

    sql_update_query = "UPDATE " + table + "SET rank = 'Elite Genin' where xp = 800"
    cursor.execute(sql_update_query)

But when I run the code, I get this error.

TypeError: loop() missing 1 required positional argument: 'ctx' 

Solution

  • The error is most likely because looping tasks are unable to use ctx directly. ctx in the context of bots (or specifically Discord bots) stands for "context" and means the message a user sends that activates the command. This is often used for commands where you need to know what the user sent, like how much of something to buy from a shop.

    However, a looping task is a function that is called in a loop. This means that you can't provide your loop function with any arguments because the loop is calling your function, not you.

    For example, say you have a command (function) getXP(ctx) that gets the XP of a user. When a user uses this command using /getXP @thisrandomGuy, the function is called with the message which is the context ctx, a person whose username is "thisrandomGuy", to find that person's XP.

    However for a looping task, you can't do that because it repeats a predetermined task. It is NOT called by you.

    For your task, the best way to work around this is to loop through your database. When you find an XP amount equal to 800 XP, find the user and the guild/server it's from and send the message.