==

Q-Consultation for every industry

Securely hold virtual meetings and video conferences

Learn More>

Want to learn more about our products and services?

Speak to us now

How to sort users using sort operators in QuickBlox JS SDK?

Artem Koltunov
19 Sep 2024
chat app built with JS SDK

Summary: In this tutorial, we’ll cover how to use sort operators within the QuickBlox JS SDK to efficiently sort user data. You’ll learn how to implement sorting based on various user attributes, such as username, email, and creation date, enhancing your app’s ability to manage and display users in a structured way. In addition to walking you through key steps, we’ll provide helpful code snippets to get you started.

Table of Contents

Introduction

Welcome to this QuickBlox developer tutorial! In this guide, we’ll dive into an essential feature for any app dealing with user management: sorting users. Whether you’re building a healthcare app, a real-time chat platform, or any user-centric solution, the ability to efficiently organize and retrieve user data can drastically enhance your app’s performance and user experience.

In this tutorial, we’ll explore how to use sort operators with the QuickBlox JS SDK to seamlessly sort users based on criteria like username, email, creation date, and more. By the end of this guide, you’ll be able to integrate these powerful sorting functionalities into your app, ensuring smooth user handling and a cleaner codebase. Let’s get started!

A note on additional resources:
Filtering and sorting users are common tasks in the business logic of applications, which is why we include a dedicated section on this topic in our official documentation for the API server and for the JS SDK.

We also provide a similar guide for Android developers, see How to sort users efficiently in your apps using QuickBlox Android SDK.

What Fields Can Be Sorted?

Before moving on to specific examples and situations, it is crucial to realize that not all model fields are suitable for filtering and sorting. Special attention should be paid to whether the field you are interested in is included in the list of fields allowed for search and sorting.

All permitted fields are listed in the “Applicable to fields” column of our JS SDK documentation.

application to fields

If the required field is not on this list, then you will need to adopt the following approach: First, retrieve all users from the server by loading them into a local collection (such as an array), and then sort by this field using sorting methods within the collection.

Examples of Searching Criteria

When using the QuickBlox Android SDK, users can be fetched based on the following criteria:

  1. created in specific time period
  2. updated in specific time period
  3. created before exact date
  4. created after exact date
  5. updated before exact date
  6. updated after exact date
  7. exclude exact email, phone number, or login

Let’s give you some examples of how and when these criteria could be implemented.

App owners will want to track the number of new enrollments, with the ability to find out how many users registered on the app on any given date. For this scenario they can implement use case 1 – Load users created in a specific time period.

There may be a situation when an organization needs to know which app users updated their app profile within a specific time period, perhaps they want to send them notifications of a special promotion or offer. This list can be achieved by use case 2 – Load users which updated in a specific time period.

It may be necessary to notify older long-term app users when the app owner updates certain policies or procedures. This cohort of older users can be fetched by use case 3- Load users created before exact date.

Alternatively, that same app owner may want to notify new app users who signed up within the last 7 days about onboarding information. In this scenario they can implement use case number 4 – Load users created after exact date.

What if app users fail to update their profiles or provide certain information. The app owner might want to send them a push notification reminding them to update. They can fetch a list of inactive users by use case number 5 – Load users who updated before exact date.

Alternatively, the app owner might need to know which users already updated their profiles. For this task, they can use use case number 6 – Load users who updated after exact date.

Lastly, there may be a scenario when we need to exclude some users from our results. For example, an organization may want to implement a black list or needs to select all customers but exclude service providers. In this case, they can implement use case 7 – Load users excluding specific email, phone number or login.

Getting Started with the JS SDK

Before using the SDK method

QB.users.listUsers(params, function(error, result){
  // Handle the result
});

Several mandatory steps must be completed:

  1. Initialize the SDK
  2. Create a user session (or log in)

The ‘ListUsersParams’ type, used as the first parameter in the listUsers method, includes search and order fields that allow developers to perform complex queries and retrieve data in an organized manner.

As the first parameter, we use an object with the following structure (typed in TypeScript)

type SearchOperator = ‘lt’ | ‘gt’ | ‘gte’ | ‘le’ | ‘eq’ | ‘ne’ | ‘between’ | ‘in’;

Field “searchOperator” has the value “between,” which means it will search for users between two parameters, in our case between two dates. The possible values could be:

gt – greater than
lt – less than
ge – greater or equal to
le – less or equal to
eq – equal
ne – not equal
between – between two values

interface SearchField {
  field: 'id' | 'full_name' | 'email' | 'login' | 'phone' | 'created_at' | 'updated_at' | 'last_request_at' | 'external_user_id' | 'facebook_id';
  param: SearchOperator;
  value: string;  // For 'in' or 'between', the value should be a comma-separated string of elements
}
 
interface OrderField {
  field: 'id' | 'full_name' | 'email' | 'login' | 'phone' | 'created_at' | 'updated_at' | 'last_request_at' | 'external_user_id' | 'facebook_id';
  sort: 'asc' | 'desc';
}
 
type ListUsersParams = {
  filter?: SearchField;
  order?: OrderField;
  page?: number;
  per_page?: number;
};

Explanation of Changes and Structure:

SearchOperator: A list of all valid filtering operators, including comparisons for greater, lesser, and between values.

SearchField:

field: Fields that are permissible for operations. This includes all fields applicable to comparison operations.

param: The type of operation, which must match one of the provided search operators.

value: A string of values used for operations. In the case of the ‘between’ or ‘in’ operators, the values should be presented in a string format with elements separated by commas (e.g., for dates, IDs, or other numeric and string data).

OrderField:

field: Fields by which data can be ordered.

sort: The direction of sorting, which can be either ‘asc’ (ascending) or ‘desc’ (descending).

ListUsersParams: The overall type for parameters of the listUsers function, including optional fields for filtering, sorting, and pagination.

Code examples in JavaScript and TypeScript

Now let’s provide some examples that demonstrate how to effectively utilize the sorting and searching mechanisms available in the QuickBlox JS SDK. The code samples below illustrate how it is possible to fetch users based on criteria such as creation or update dates, and exclusion filters for emails, phone numbers, or logins.

Here is the code for a function that retrieves a list of users created between two specified dates, sorted in ascending order, with 50 users per page. It includes all necessary steps for initializing the SDK and creating a session.

Load users created in a specific time period

function TestGetListUsers(): void {
    const config = {
        debug: true,
    };
    const APPLICATION_ID = 0; // Your Application ID from admin panel
    const AUTH_KEY = "YOUR_AUTH_KEY_FROM_ADMIN_PANEL";
    const AUTH_SECRET = "YOUR_AUTH_SECRET_FROM_ADMIN_PANEL";
    const ACCOUNT_KEY = "YOUR_ACCOUNT_KEY_FROM_ADMIN_PANEL";
    QB.init(
        APPLICATION_ID,
        AUTH_KEY,
        AUTH_SECRET,
        ACCOUNT_KEY,
        config
    );

    const paramsSession = { login: 'YOUR_LOGIN', password: "YOUR_PASSWORD" };

    QB.createSession(paramsSession, (error, sessionResult) => {
        if (error) {
            console.error('Error creating session:', error);
            return;
        }

        const userParams: ListUsersParams = {
            filter: {
                field: "created_at",
                param: 'between',
                value: '2021-01-01, 2021-05-06'
            },
            order: {
                field: 'created_at',
                sort: 'asc'
            },
            page: 1,
            per_page: 50
        };

        console.log('Attempting to list users...');
        QB.users.listUsers(userParams, (error, users) => {
            if (error) {
                console.error('Error retrieving user list:', error);
                return;
            }
            console.log('Users list retrieved successfully:', users);
        });
    });
}

Therefore, to modify the search criteria, it is necessary to change the values within the userParams structure. We have already discussed the case “Load users created in a specific time period” above. Below, we will demonstrate how to configure this structure for other examples.

Load users who updated in specific time period

const userParams: ListUsersParams = {
            filter: {
                field: "updated_at",
                param: 'between',
                value: '2021-01-01, 2021-05-06'
            },
            order: {
                field: 'created_at',
                sort: 'asc'
            },
            page: 1,
            per_page: 50
        };

Load users created before exact date

const userParams: ListUsersParams = {
            filter: {
                field: " created_at ",
                param: 'lt',
                value: '2021-05-06'
            },
            order: {
                field: 'created_at',
                sort: 'asc'
            },
            page: 1,
            per_page: 50
        };

Load users created after exact date

const userParams: ListUsersParams = {
            filter: {
                field: " created_at ",
                param: 'gt',
                value: '2021-05-06'
            },
            order: {
                field: 'created_at',
                sort: 'asc'
            },
            page: 1,
            per_page: 50
        };

Load users updated before exact date

const userParams: ListUsersParams = {
            filter: {
                field: "updated_at",
                param: 'le',
                value: '2021-05-06'
            },
            order: {
                field: 'created_at',
                sort: 'asc'
            },
            page: 1,
            per_page: 50
        };

Load users updated after exact date

const userParams: ListUsersParams = {
            filter: {
                field: "updated_at",
                param: 'ge',
                value: '2021-05-06'
            },
            order: {
                field: 'created_at',
                sort: 'asc'
            },
            page: 1,
            per_page: 50
        };

Load users which exclude exact email

const userParams: ListUsersParams = {
            filter: {
                field: "email",
                param: 'ne',
                value: "test@test.com"; //our email which you will exclude
            },
            order: {
                field: 'created_at',
                sort: 'asc'
            },
            page: 1,
            per_page: 50
        };

Load users which exclude exact phone number

const userParams: ListUsersParams = {
            filter: {
                field: "phone",
                param: 'ne',
                value: "831882113";
            },
            order: {
                field: 'created_at',
                sort: 'asc'
            },
            page: 1,
            per_page: 50
        };

Load users which exclude exact phone login

const userParams: ListUsersParams = {
            filter: {
                field: "login",
                param: 'ne',
                value: "testUser";
            },
            order: {
                field: 'created_at',
                sort: 'asc'
            },
            page: 1,
            per_page: 50
        };

A Note on Pagination

In all the requests in our examples, we used two fields: page and per_page, which can be utilized to implement pagination as follows.

You should repeat requests, increasing the value of the offset (skip) by the amount of the limit until the number of elements in the response is less than the limit. In other words, the number of retrieved elements will be less than the sum of the skip and the limit.

For example, if we have a total of 250 messages and we want to receive 100 messages per page, then:

Step 1: Set the limit to 100, and initially set the skip to 0.
Response 1: In our list, there are 100 elements. The limit is set to 100. The offset (skip) is 0. Check: list >= limit + skip (100 >= 100 + 0) – the condition is met. We can repeat.

Step 2: Set a new limit of 100. Set the offset (skip) to the number of already retrieved elements (100).
Response 2: In our list, there are 100 elements. Check: the length of the array retrieved (100 + 100) >= limit + skip (200 >= 200) – the condition is met.

Step 3: The limit remains 100. Increase the offset (skip) by the size of the retrieved list (200).
Response 3: In our list, there are 50 new elements. Check: the length of the retrieved array (250) < limit + skip (300) - the condition is not met. Thus, the function for retrieving users with pagination should be similar to the following.

function TestGetListUsers(): void {
    const config = {
        debug: true,
    };
    const APPLICATION_ID = 0; // Your Application ID from admin panel
    const AUTH_KEY = “YOUR_AUTH_KEY_FROM_ADMIN_PANEL”;
    const AUTH_SECRET = “YOUR_AUTH_SECRET_FROM_ADMIN_PANEL”;
    const ACCOUNT_KEY = “YOUR_ACCOUNT_KEY_FROM_ADMIN_PANEL”;
    QB.init(
        APPLICATION_ID,
        AUTH_KEY,
        AUTH_SECRET,
        ACCOUNT_KEY,
        config
    );

    const paramsSession = { login: ‘YOUR_LOGIN’, password: “YOUR_PASSWORD” };

    QB.createSession(paramsSession, async (error, sessionResult) => {
        if (error) {
            console.error(‘Error creating session:’, error);
            return;
        }

        let totalFetched = 0;
        const limit = 100;
        let page = 1;
        let continueFetching = true;

        while (continueFetching) {
            const userParams = {
                filter: {
                    field: “created_at”,
                    param: ‘between’,
                    value: ‘2021-01-01, 2021-05-06’
                },
                order: {
                    field: ‘created_at’,
                    sort: ‘asc’
                },
                page: page,
                per_page: limit
            };

            console.log(`Fetching users from page ${page} with limit ${limit}`);
            // We need to wrap the QB.users.listUsers to use await with it
            await new Promise((resolve, reject) => {
                QB.users.listUsers(userParams, (error, result) => {
                    if (error) {
                        console.error(‘Error retrieving user list:’, error);
                        reject(error);
                        return;
                    }
                    const users = result.users || [];
                    console.log(`Fetched ${users.length} users this batch.`);
                    totalFetched += users.length;

                    if (users.length < limit || totalFetched >= result.total) {
                        continueFetching = false;
                    } else {
                        page++; // Prepare for the next page
                    }
                    resolve(result);
                });
            });
        }

        console.log(‘All users have been fetched or no more users to fetch.’);
    });
}

Wrapping Up

We hope this guide has served as a helpful resource for understanding and applying user sorting and filtering techniques in your applications using QuickBlox. Whether you’re looking to manage user data based on specific timeframes or exclude particular entries, the flexibility of the QuickBlox JS SDK caters to a broad range of requirements.

For further details and technical support, we invite you to join our discussions on our Discord server, where you can find a wealth of information and interact directly with developers. Your contributions and interactions help enrich our community and improve our documentation and tool offerings.

Have Questions? Need Support?

Join the QuickBlox Developer Discord Community, where you can share ideas, learn about our software, & get support.

Join QuickBlox Discord

Leave a Comment

Your email address will not be published. Required fields are marked *

Read More

Ready to get started?

QUICKBLOX
QuickBlox post-box