I want to create a bot that can tell me the list of the first 300 members of my server. Is this possible with Discord.js? Any help would be appreciated. I just don't know where to start
Assuming you want to get the first 300 members that joined the guild, you can use the GuildMember.joinedAt property. You would go through these steps:
Fetch all the members in the guild: you can use Guild.members.fetch() for that
Sort them by the date you get from the joinedAt property
Get the first 300
Here's how I would do it:
guild.members.fetch() // Fectch all the members in the guild
.then(members => {
let first300 = members
.sort((a, b) => a.joinedAt - b.joinedAt) // Order them by they date the joined the guild
.first(300) // Take the first 300
})
Like syntle asked it depends which kinda but, here's the first 300 to fetch:
Might not work since there might be an already set limit of members you can fetch
const members = await <Guild>.members.fetch({ limit: 300 });
//or if you are fine with cached
const members = <Guild>.members.cache.array();
members.length = 300;
Related
I have one counter left to create. And for this one I don't really know which direction to take.
I believe counting the number of members with the boost role will be wrong as members can have boosted the server twice.
module.exports = async(client) => {
const guild = client.guilds.cache.get('912706237806829598');
setInterval(async () => {
const boostCount = (await guild.members.fetch()).filter(????????).size;
const channel = guild.channels.cache.get('960832075349499925');
channel.setName(`╭🌕・Boosts: ${boostCount.toLocaleString()}`);
console.log('Updating Boost Count');
console.log(boostCount);
}, 600000);
}
I don't know if I get achieve this by putting something inside filter. Looking at the members is probably not correct as well.
Really need some assistance for this one.
Making use of guild.premiumSubscriptionCount would help you out. It will count all the boosts in total including double boosts.
So to define users for things like displaying avatars, etc. i've been using this;
var user = message.mentions.users.first() || message.author;
But i've been trying to figure out how people have been able to define users without mentions. Example - my command requires me to tag someone whereas Dyno can do it with partial names. Any tips would be great, thanks!
An easy way to do so would probably be using the .find() function, where you can search for a certain object based on a method.
For example, if we were to have an args variable in our callback (Very easy to do so using a proper command handler - I'd suggest looking for tutorials if you aren't familiar with command handlers), and we were to ask a user to pass in a member's name, we could very easily get the user object using:
const user = message.guild.users.cache.find(user => user.username === args[0]);
// Keep in mind, 'user' is just a variable I've defined. It could also be 'monke => monke.username' if you wish.
Or, if we were to ask for their ID, we could use the .get() function to get the user object by ID:
const user = message.guild.users.cache.get(args[0]);
Do keep in mind it's not the greatest to have these kinds of object getting functions, as there are always multiple conflicts that could occur whilst getting the object, such as if there are multiple users with the same name/tag. I'd highly recommend sticking to your mention-based user objects, as it's the most accurate and non-conflicting method.
Every guild has a list of members which you can search through by enabling the Server Members Intent for your bot via the Discord Developer Portal. Once you have done that, you can fetch a collection of all members of a guild by doing
guild.members.cache;
You can then search this collection to find a member based on a search query using .includes(), .filter() or something similar. For example:
let query = "something";
let list = guild.members.cache.filter(member => member.user.username.includes(query));
console.log(Object.entries(list));
// expected output: list of all server members who's usernames contain "something"
You could also use the .find() method (since a collection is a map) to return a member with an exact username:
let member = guild.members.cache.find(member => member.user.username === query);
console.log(member.tag);
// expected output: tag of the user who's username is "something"
This is as simple as that:
var user = message.guild.members.cache.find(u => u.user.username.toUpperCase() === args.join(" ") || u.user.username.toLowerCase() === args.join(" ") || u.user.username === args.join(" "))
This will find the user on the current guild but you can also search your bot for this user by doing:
var user = client.users.cache.find(u => u.username.toUpperCase() === args.join(" ") || u.username.toLowerCase() === args.join(" ") || u.username === args.join(" "))
I have to assume that you already defined args and client. The example above will find users just by typing their name. toUpperCase means if you type the username in uppercase letters it will find the users anyways. toLowerCase means if you type the username in lowercase letters it will find the user as well. And you could also just type the username as it is. || means or so you can decide how you write the username, it will be found anyways.
We are building a content app using Firestore.
The basic requirement is that there is one master collection, let's say 'content'. The number of documents could run into 1000s.
content1, content2, content3 ... content9999
We want to serve our users with content from this collection, making sure they don't see the same content twice, and every time they are in the app there's new content for them.
At the same time, we don't want the same sequence of our content to be served to each user. Some randomisation would be good.
user1: content9, content123, content17, content33, content902 .. and so on
user2: content854, content79, content190, content567 ... and so on
I have been breaking my head as to how without duplicating the master collection can we possibly achieve this solution. Duplicating the master collection would just be so expensive, but will do the job.
Also, how can we possibly write cost-effective and performance-optimised queries especially when we want to maintain randomisation in the sequence of these content pieces?
Here is my suggestion. Please view it as pseudo-code as I did not run it.
If the content document ids are not previsible
You have to store and maintain which user has seen which content, for example in a collection: /seen/uid_contentId
See here a clever way to get a random document from a collection. You need to store the size of the collection, perhaps as a document in another collection. So here is how you could do it:
const snapshot = await firestore.doc(`/userSeen/${uid}`).get(); // do it only once
const alreadySeen = snapshot.exists ? snapshot.data.contents : [];
async function getContent(uid) {
for (let trials = 0; trials < 10; trials++) { // limit the cost
const startAt = Math.random() * contentCollectionSize;
const snapshot = await firestore.collection("/contents").startAt(startAt).limit(1).get();
const document = snapshot.empty ? null : snapshot.docs[0]; // a random content
if(document.exists && !alreadySeen.includes(document.id)) {
alreadySeen.push(document.id);
await firestore.doc(`/userSeen/${uid}`).set({contents: arrayUnion(document.id)}); // mark it as seen
return document;
}
}
return null;
}
Here you may have to make several queries to Firestore (capped to 10 to limit the cost), because you are not able to compute the content document ids on the client side.
If the content document ids follow a simple pattern: 1, 2, 3, ...
To save up costs and performance, you should store all the seen contents for each user in a single document (the limit is 1MB, that is more than 250,000 integers!). Then you download this document once per user, and check on the client side if a random content was already seen.
const snapshot = await firestore.doc(`/userSeen/${uid}`).get(); // do it only once
const alreadySeen = snapshot.exists ? snapshot.data.contents : [];
async function getContent(uid) {
let idx = Math.random() * contentCollectionSize;
for (let trials = 0; trials < contentCollectionSize; trials++) {
idx = idx + 1 < contentCollectionSize ? idx + 1 : 0;
if(alreadySeen.includes(idx)) continue; // this shortcut reduces the number of Firestore queries
const document = await firestore.doc(`/contents/${idx}`).get();
if(document.exists){
alreadySeen.push(idx);
await firestore.doc(`/userSeen/${uid}`).set({contents: arrayUnion(idx)}); // mark it as seen
return document;
}
}
return null;
}
As you can see, this is much cheaper if you use previsible document ids for your content. But perhaps someone will have a better idea.
I have another idea. You could generate scalars of content :D
Create another collection - scalars
Add field type array
Code a function which will walk through content collection and will generate sets of content items randomly or taking into account other attributes like popularity, demographic, behaviour of users.
Generate 1000 of sets of content items in scalars collection, and do this once a month for example.
You can even measure effectiveness of each scalar in the context of attracting back users and promote those that are more atractive.
Once you have collection of scalars containing sets of collection items, you can assign users to a scalar. And present content items accordingly.
im trying to make a server/guild side variable for my bot (have a variable that has a different value in each server). I dont know how to make that so i really need help... How can i get a variable to have a different value in each server?
You should use a discord.js Collection, which is:
A Map with additional utility methods. This is used throughout discord.js rather than Arrays for anything that has an ID, for significantly improved performance and ease-of-use.
A Map object holds key-value pairs and remembers the original insertion order of the keys. Any value may be used as either a key or a value. Here's a quick demo:
// let's say we had two people: John and Sarah
const people = new Map();
// each of them were a different age
people.set('John', 25); // in this example, 'John' is the key, and 25 is the value
people.set('Sarah', 19); // in this example, 'Sarah' is the key, and 25 is the value
// each person has an individual age
// you can `get()` the key, and it will return the value
console.log(`Sarah is ${people.get('Sarah')} years old.`);
console.log(`John is ${people.get('John')} years old.`);
You can use this type of format to create a collection with each key being a different guild ID, and each value being... whatever you want. Here's an example:
// const { Collection } = require('discord.js');
const guilds = new Collection();
// put some data in an object as the key
guilds.set("Guild ID", {
name: "Guild Name",
welcomeMsg: "Welcome new person!",
welcomeChannel: "...",
blacklistedIDs: ["123456", "67890"],
});
client.on("guildMemberAdd", (member) => {
const guild = guilds.get(member.guild.id); // get the collection element via guild id
if (!guild) return;
// then access all its data!
console.log(`Somebody joined ${guild.name}`);
if (guild.blacklistedIDs.includes(member.id)) return member.kick();
guild.welcomeChannel.send(guild.welcomeMsg);
});
I believe Tin Nguyen posted this idea as a comment, I am just elaborating on that. To achieve what you want, you can use what is known as a "data dictionary" which is basically just a file storing a list of something.
For your specific use case, you can use a simple JSON file to store your variables. For each guild that your bot is in, you can add a new object to a list of objects in a local JSON file called variable.json for example.
Here is an idea of what it might look like:
[
{
"guild": "INSERT GUILD ID",
"value": "INSERT VARIABLE VALUE"
},
]
guild will store the id of the guild, so you can identify the correct value. To get the value stored in value for a certain guild, all you have to do is loop through the JSON file, and find the object with the correct guild ID:
const variables = require("variable.json"); //imports the JSON data
const value; //creates a new variable
for (i = 0; i < variables.length; i++) { //loops through the guilds
if (variables[i].guild === message.guild.id) { //if the IDs are the same...
value = variables[i].value; //...sets "value" to the retrieved value
}
}
This of course relies on the fact that your bot also adds each guild it joins to the list. To do this, you can use the guildCreate event. Documentation for this can be found here.
I was wondering if it is possible to list every member within a specific role.
If possible to make it so I can search for every role without changing the code, and changing roleid..
There is multiple ways to get a list of every GuildMember that has a specific Role.
You can use .members Role property to get a Collection of GuildMember
Example :
// Getting a Collection of all GuildMember that have the role stored in "myRole" var.
let myRole = client.guilds.resolve("651196009896214543").roles.cache.get("651197514506305555");
let members = myRole.members
Or you can filter all GuildMember of a Guild like that :
let members = client.guilds.resolve("651196009896214543").members.cache;
members = members.filter(guildMember => guildMember.roles.cache.has("651197514506305555"));