7

I'm trying to figure out a way to use loops to get old messages on discord using fetchMesasges() and before. I'd like to get more than the 100 limit using a loop but I cannot figure it out, and every post I can find only discuss how to use loops to DELETE more than the 100 limit, I just need to retrieve them.

I'm new to coding and javascript in particular so I'm hoping someone can give me a nudge in the right direction.

Here is the only way I could manage to retrieve messages that are farther than 100 back(after many failed attempts at using loops):

channel.fetchMessages({ limit: 100 })
    .then(msg => {
        let toBeArray = msg;
        let firstLastPost = toBeArray.last().id;

        receivedMessage.channel
            .fetchMessages({ limit: 100, before: firstLastPost })
            .then(msg => {
                let secondToBeArray = msg;
                let secondLastPost = secondToBeArray.last().id;

                receivedMessage.channel
                    .fetchMessages({ limit: 100, before: secondLastPost })
                    .then(msg => {
                        let thirdArray = msg;
                        let thirdLastPost = thirdArray.last().id;

                        receivedMessage.channel
                            .fetchMessages({ limit: 100, before: thirdLastPost })
                            .then(msg => {
                                let fourthArray = msg;
                            });
                    });
            });
    });
Federico Grandi
  • 6,785
  • 5
  • 30
  • 50
D. Overton
  • 71
  • 1
  • 1
  • 5

2 Answers2

12

What you can do is use an async/await function and a loop to make sequntial requests

async function lots_of_messages_getter(channel, limit = 500) {
    const sum_messages = [];
    let last_id;

    while (true) {
        const options = { limit: 100 };
        if (last_id) {
            options.before = last_id;
        }

        const messages = await channel.fetchMessages(options);
        sum_messages.push(...messages.array());
        last_id = messages.last().id;

        if (messages.size != 100 || sum_messages >= limit) {
            break;
        }
    }

    return sum_messages;
}
Jason
  • 779
  • 1
  • 9
  • 30
  • this worked great for me. I'm still having a little trouble iterating through separate arrays since .push creates an array containing separate arrays for each 100 posts fetched. I'm trying to find a way to make concat work. Anyway, thanks for the feedback, it helped a ton! – D. Overton Mar 14 '19 at 06:08
  • Have a read of the [docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) for `.concat();` – Pentium1080Ti Mar 14 '19 at 07:31
  • @D.Overton I've updated the example to use a spread operator (`sum_messages.push(...messages.array());`) – Jason Mar 14 '19 at 16:17
  • @Jason I'm gonna have a read up on the [docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) to familiarize myself with it more. But I think that's exactly what I needed. Thanks. – D. Overton Mar 15 '19 at 02:04
  • I think you're missing the length in the last condition `sum_messages.length >= limit` – TechnoTim Jul 18 '21 at 15:00
2

This works for me using discord.js v 11.5.1 and TypeScript. It is an updated version of Jason's post.

The reason I used this is because: DiscordAPI limit maxes out at 100 for fetching messages and the deprecated TextChannel#fetchMessages() method no longer exists.

I updated it to use the TextChannel#messages object's fetch(options?: ChannelLogsQueryOptions, cache?: boolean) method to fetch Collections of 100 or less messages.

async function getMessages(channel: TextChannel, limit: number = 100): Promise<Message[]> {
  let out: Message[] = []
  if (limit <= 100) {
    let messages: Collection < string, Message > = await channel.messages.fetch({ limit: limit })
    out.push(...messages.array())
  } else {
    let rounds = (limit / 100) + (limit % 100 ? 1 : 0)
    let last_id: string = ""
    for (let x = 0; x < rounds; x++) {
      const options: ChannelLogsQueryOptions = {
        limit: 100
      }
      if (last_id.length > 0) {
        options.before = last_id
      }
      const messages: Collection < string, Message > = await channel.messages.fetch(options)
      out.push(...messages.array())
      last_id = messages.array()[(messages.array().length - 1)].id
    }
  }
  return out
}
SeqSEE
  • 94
  • 8
  • I've also updated the snippet slightly by adding the return type of the function and changing it from a public method to a static function. – SeqSEE Feb 11 '20 at 13:30