Leaderboard in quick.db

Hello.

I want to make a leaderboard command with quick.db.
How can I do it?

2 Likes

What kind of leaderboard do you want to make?

Are you storing data already? Are you having problems storing data or sorting it?

My code is already storing data. I have problems with sorting it and displaying only 10 per page.

The leaderboard I want to make is:

  • All the users are on it;
  • Only 10 per page.

There is no method in quick.db to sort the data.

But maybe you can use db.all() which give you an array.

Then array.sort(...)

Finally a loop to make the ā€˜paginationā€™.

Tell us if you have a problem with the code. Maybe you can share how is the structure of your db.all() result array

Well, Iā€™ve already saw the quick.db docs, ADN thereā€™s a say to sort ALL the users. And I already tryed many times to use the loops and pagination. Iā€™m asking here because I really donā€™t know how to do it.

I find a way to sort the data with an older version. In the new one there is no function to sort it, so you have to use array.sort()

OLD VERSION [6.3.2]

package.json

...
  "dependencies": {
    ...,
    "quick.db": "6.3.2"
  }
...

leaderboard.js

async function getLeaderboard (page, per_page) {
  // Get all data sorted. Replace string
  const resp = await db.startsWith('string', {sort: '.data'});

  // Pagination
  var page = page || 1,
  per_page = per_page || 10,
  offset = (page - 1) * per_page,

  paginatedItems = resp.slice(offset).slice(0, per_page),
  total_pages = Math.ceil(resp.length / per_page);
  let end = {
    page: page,
    per_page: per_page,
    pre_page: page - 1 ? page - 1 : null,
    next_page: (total_pages > page) ? page + 1 : null,
    total: resp.length,
    total_pages: total_pages,
    data: paginatedItems
  };
  
  // RESULT
  return end;
}

NEW VERSION [7.0.0-b22]

If you use the updated version of quick.db you have to sort manually your data

leaderboard.js

function getLeaderboard (page, per_page) {
  // Get all data not sorted
  const resp = db.all();
  
  // Sort from higher to lower
  resp.sort((a, b) => (a.data < b.data) ? 1 : -1);
  
  /* Pagination: copy the code from last example */

  // RESULT
  return end;
}

The return data for both examples is something like this:

getLeaderboard(1, 10);

{ page: 1,
  per_page: 10,
  pre_page: null,
  next_page: 2,
  total: 200,
  total_pages: 20,
  data: 
   [ { ID: 'Nick[83]', data: 9972 },
     { ID: 'Nick[182]', data: 9907 },
     { ID: 'Nick[106]', data: 9899 },
     { ID: 'Nick[173]', data: 9895 },
     { ID: 'Nick[116]', data: 9886 },
     { ID: 'Nick[142]', data: 9858 },
     { ID: 'Nick[148]', data: 9831 },
     { ID: 'Nick[114]', data: 9803 },
     { ID: 'Nick[153]', data: 9769 },
     { ID: 'Nick[189]', data: 9548 } ] }

OK. It seems to work. But now I have the problem with sending an embed like this:

Leaderboard
Page: 1

+++
^^^^ Here I want to show for each user: ā€˜Username: usercoins coinsā€™

Edit: And I want to show only the coins. I use the db to XP, coins, and others.

  // Pagination
  var page = page || 1,
  per_page = per_page || 10,
  offset = (page - 1) * per_page,

  paginatedItems = resp.slice(offset).slice(0, per_page),
  total_pages = Math.ceil(resp.length / per_page);
  
  // Leaderboard Message -> Make your message as you want.
  var leaderboardMessage;
  for (var i in paginatedItems) {
    leaderboardMessage += `${paginatedItems[i].ID} | Data: ${paginatedItems[i].data} \n`;
  }
  
  let end = {
    page: page,
    per_page: per_page,
    pre_page: page - 1 ? page - 1 : null,
    next_page: (total_pages > page) ? page + 1 : null,
    total: resp.length,
    total_pages: total_pages,
    data: paginatedItems,
    message: leaderboardMessage
  };
 
  // RESULT
  return end;

OK. So, all I have to do for the message is put leaderboardMessage in the description field, right?
And can I replace db.all() by db.all(ā€˜coinsā€™)?

I donā€™t know about db.all('coins')

But yeah. You should know, with all the information I gave to you, how you want to make your own command

OK. I used the old version, and it works fine, but it isnā€™t sending the message.
Hereā€™s my code: https://pastebin.com/Ps9i9SuW

Hey there, @TheBigerGamer!

The above post is not ā€œat allā€ related to Discord.js. Please refrain from posting such questions in wrong categories.

I only asked because Iā€™m using it in my discord.js bot.

Line 10

const resp = await db.startsWith('string', {sort: '.data'});

You should change ā€œstringā€ for what your query to the database.

The db.startsWith(...) function is going to searh all the keys of your db wich starts with the first argument. In this example start with ā€œstringā€

Take out the return end; at your line 38. This is where your code is stop reading so it doesnā€™t send message.

You can add return message.channel.send(topembed) in the 46 line

It gave me this:


And Iā€™m seeing that the code donā€™t get the usernameā€¦

Itā€™s a range error :woman_shrugging:

Your RichEmbed is exceeding the limit, the maximum limit is 256 characters for a RichEmbed field.

EDIT: You can split them up into two embed if it exceeds the limit

Well, I finally changed the code, and now it shows the leaderboard, but I have THIS:error

The code is this:

const db = require('quick.db');

exports.run = async (bot, message, args) => {
  async function getLeaderboard (page, per_page) {
  // Get all data not sorted
  const resp = await db.startsWith('moons_', {sort: '.data'});
  // Pagination
    
  var page = page || 1,
  per_page = per_page || 5,
  offset = (page - 1) * per_page,

  paginatedItems = resp.slice(offset).slice(0, per_page),
  total_pages = Math.ceil(resp.length / per_page);
    
    let id = resp.slice('moons_')
      console.log(id)
    
  
  // Leaderboard Message -> Make your message as you want.
  var leaderboardMessage;
  for (var i in paginatedItems) {
    leaderboardMessage += `${paginatedItems[i].ID} | Moons: ${paginatedItems[i].data} \n`;
  }
  
  let end = {
    page: page,
    per_page: per_page,
    pre_page: page - 1 ? page - 1 : null,
    next_page: (total_pages > page) ? page + 1 : null,
    total: resp.length,
    total_pages: total_pages,
    data: paginatedItems,
    message: leaderboardMessage
  };

  // RESULT
    console.log(leaderboardMessage)
    const topembed = new Discord.RichEmbed()
    .setColor(16777215)
    .setAuthor('Top de Moons')
    .setDescription('Top de Moons do S1mple', `PƔgina: ${page}`)
    .addField(leaderboardMessage, `Top 5`)
    .setFooter(`PƔgina: ${page} | Por pƔgina: ${per_page}`)
    return message.channel.send(topembed)
}
  getLeaderboard (1, 5)
  
}
module.exports.command = {
    name: 'topmoons',
    aliases: ['leaderboard', 'top'],
    description: 'Veja os mais ricos do servidor!',
    category: "Economia",
    usage: 'topmoons',
    enabled: false
}

You see paginatedItems[i].ID is returning undefined for the first element of the array, from what I could gather.

I already saw that. But whatā€™s the solution?