Channel Pagination

LAST EDIT Apr 08 2021

The channel query endpoint allows you to paginate the list of messages, watchers, and members for one channel. To make sure that you are able to retrieve a consistent list of messages, pagination does not work with simple offset/limit parameters but instead, it relies on passing the ID of the messages from the previous page.

For example: say that you fetched the first 100 messages from a channel and want to lead the next 100. To do this you need to make a channel query request and pass the ID of the oldest message if you are paginating in descending order or the ID of the newest message if paginating in ascending order.

Use the id_lt parameter to retrieve messages older than the provided ID and id_gt to retrieve messages newer than the provided ID.

The terms id_lt and id_gt stand for ID less than and ID greater than.

ID-based pagination improves performance and prevents issues related to the list of messages changing while you’re paginating. If needed, you can also use the inclusive versions of those two parameters: id_lte and id_gte.

1
2
3
4
5
6
7
// the id of the last message on the page 
const lastMessageId = messages[0].id; 
const result = await channel.query({ 
    messages: { limit: 20, id_lt: lastMessageId } , 
    members: { limit: 20, offset: 0 } , 
    watchers: { limit: 20, offset: 0 }, 
});
1
2
3
4
5
final response = await channel.query( 
  messagesPagination: PaginationParams(limit: 2, lessThanOrEqual: "123"), 
  membersPagination:  PaginationParams(limit: 2, offset: 0), 
  watchersPagination: PaginationParams(limit: 2, offset: 0), 
);
1
2
3
4
5
$messages = $channel->query([ 
		'messages' => ['limit'=>2, 'id_lte' => '123'],  
		'members'  => ['limit'=>2, 'offset' => 0], 
		'watchers' => ['limit'=>2, 'offset' => 0] 
]);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// messages 
 
let controller = chatClient.channelController(for: .init(type: .messaging, id: "general")) 
 
controller.loadNextMessages(limit: 25) { error in 
    if let error = error { 
        // handle error 
        print(error) 
    } else { 
        // access messages 
        print(controller.messages) 
         
        controller.loadNextMessages(limit: 25) { error in 
            // handle error / access messages 
            print(error ?? controller.messages) 
        } 
    } 
} 
 
// members 
 
let memberController = chatClient.memberListController(query: .init(cid: .init(type: .messaging, id: "general"))) 
 
memberController.loadNextMembers(limit: 25) { error in 
    if let error = error { 
        // handle error 
        print(error) 
    } else { 
        // access members 
        print(memberController.members) 
         
        memberController.loadNextMembers(limit: 25) { error in 
            // handle error / access members 
            print(error ?? memberController.members) 
        } 
    } 
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
val channelClient = client.channel("messaging", "general") 
val pageSize = 10 
 
// Request for the first page 
val request = QueryChannelRequest() 
    .withMessages(pageSize) 
 
channelClient.query(request).enqueue { result -> 
    if (result.isSuccess) { 
        val messages: List<Message> = result.data().messages 
        if (messages.size < pageSize) { 
            // All messages loaded 
        } else { 
            // Load next page 
            val nextRequest = QueryChannelRequest() 
                .withMessages(LESS_THAN, messages.last().id, pageSize) 
            // ... 
        } 
    } else { 
        // Handle result.error() 
    } 
}
1
2
3
4
5
6
7
8
9
# the id of the last message on the page 
last_message_id = messages[0]["id"] 
 
# pick the parts you need; messages, members or watchers  
result = channel.query( 
    messages={"limit": 50, "id_lt": last_message_id}, 
    members={"limit": 10, "offset": 0}, 
    watchers={"limit": 20, "offset": 0}, 
)
1
2
3
4
5
6
7
8
9
# the id of the last message on the page 
last_message_id = messages[0]["id"] 
 
# pick the parts you need; messages, members or watchers  
result = channel.query({ 
    'messages' => {'limit' => 50, 'id_lt' => last_message_id}, 
    'members' => {'limit' => 50, 'offset' => 0}, 
    'watchers' => {'limit' => 50, 'offset' => 0}, 
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
ChannelClient channelClient = client.channel("messaging", "general"); 
int pageSize = 10; 
 
// Request for the first page 
QueryChannelRequest request = new QueryChannelRequest() 
        .withMessages(pageSize); 
 
channelClient.query(request).enqueue(result -> { 
    if (result.isSuccess()) { 
        List<Message> messages = result.data().getMessages(); 
        if (messages.size() < pageSize) { 
            // All messages loaded 
        } else { 
            // Load next page 
            Message lastMessage = messages.get(messages.size() - 1); 
            QueryChannelRequest nextRequest = new QueryChannelRequest() 
                    .withMessages(LESS_THAN, lastMessage.getId(), pageSize); 
            // ... 
        } 
    } else { 
        // Handle result.error() 
    } 
});

For members and watchers, we use limit and offset parameters.

Soon we will create friendlier aliases for id_lt and id_gt. Our best candidates are before_id and after_id, let us know if you have any feedback or suggestion!
The maximum number of messages that can be retrieved at once from the API is 300.