pagination using cloud firestore in ASP.NET Core

Hi,

I am trying to implement pagination, filtering, searching using cloud firestore in ASP.NET Core ( DataGrid ) by using DataManagerRequest and UrlAdaptor. I know how to do that using SQL and entity framework, but it is different from this, because firestore works very differently. I hope you have a sample for that. Please help.

Thank you

Regards

Ahmed Mohammedali


6 Replies

MS Manivel Sellamuthu Syncfusion Team July 22, 2021 12:11 PM UTC

Hi Ahmed, 

Sorry for the delay getting back to you. 

We have analyzed your query and we could see that you like to perform the paging action at server side. While Performing paging it will send the skip and take query to the API. when using the UrlAdaptor, you need to return the data as JSON from the controller action and the JSON object must contain a property as result with dataSource as its value and one more property count with the dataSource total records count as its value. 
 
To handle the Grid actions in the server side using URL Adaptor we have class named DataOperations. It will  process grid actions such as Paging, Sorting, Searching, and Filtering. Since you are using the custom API for your requirement you can handle the server side actions as demonstrated below. 
 
 
public ActionResult UrlDatasource([FromBody]DataManagerRequest dm) 
// in the dm variable you can get the skip and take values sent from client side 
        { 
           // You need to perform the paging in your api and return the data as result and count below 
             . . . 
            return dm.RequiresCounts ? Json(new { result = DataSource, count = count }) : Json(DataSource); 
        } 


Client side request in the network tab: 

 

Before preparing sample for your query, could you please share the below details, which will be helpful for us to validate further about your requirement. 

  1. Share the complete Grid code and server side code example
  2. Steps or documentation that you have used to create the fire store API
  3. If possible, please share the simple fire store API sample to integrate the Grid server side actions in the sample

Regards, 
Manivel 



AM Ahmed Mohammedali July 22, 2021 01:25 PM UTC

Hi,

Thank you for your reply. Before answering your questions, I want to point out that I implemented a similar grid for the part of my data stored in MSSQL, and it works perfectly. So, I am trying to use the same concept here but I found that cloud firestore API is very different.

Here is my server-side code:

 public IActionResult  Index()

        { 

            return View();

        }


Here is the function being called via ajax , which I am trying to implement and complete:


 public async Task<IActionResult> UrlDatasourceAsync([FromBody] DataManagerRequest dm)

        {

            CollectionReference collection = _firestore.Collection("students");

            Query query;


            if (dm.Search != null && dm.Search.Count > 0)

            {

                //DataSource = operation.PerformSearching(DataSource, dm.Search); //Search

            }

            if (dm.Sorted != null && dm.Sorted.Count > 0) //Sorting

            {

                //DataSource = operation.PerformSorting(DataSource, dm.Sorted);

            }

            if (dm.Where != null && dm.Where.Count > 0) //Filtering

            {

                //DataSource = operation.PerformFiltering(DataSource, dm.Where, dm.Where[0].Operator);

            }

            int count = (await collection.GetSnapshotAsync()).Count();

            if (dm.Skip != 0)

            {

                //DataSource = operation.PerformSkip(DataSource, dm.Skip); //Paging

            }

            if (dm.Take != 0)

            {

                //DataSource = operation.PerformTake(DataSource, dm.Take);

            }


            query = collection.Limit(dm.Take == 0 ? 10 : dm.Take);


            var list = new List<StudentViewModel>();

            foreach (DocumentSnapshot doc in await query.GetSnapshotAsync())

            {

                list.Add(doc.ConvertTo<StudentViewModel>());

            }



            var ss = new JsonSerializerSettings();

            ss.ContractResolver = new DefaultContractResolver();


            return dm.RequiresCounts ? Json(new { result = list, count = count }, ss) : Json(list);

        }



Here is the grid code:


<ejs-grid id="Grid" allowPaging="true" allowSorting="true" allowFiltering="true" toolbar="@(new List<string>() { "Search"})" load="actionComplete" created="gridCreated" dataBound="actionComplete" actionComplete="actionComplete" actionBegin="actionBegin">

            <e-grid-filterSettings type="Excel"> </e-grid-filterSettings>

            <e-grid-pagesettings pageSize="10" pageSizes="true"></e-grid-pagesettings>

            <e-data-manager url="@Url.Action("UrlDatasource","RegisteredStudents")" adaptor="UrlAdaptor"></e-data-manager>

            <e-grid-columns>

                <e-grid-column field="Name" headerText="Name"></e-grid-column>

                <e-grid-column field="AttendantCategry" headerText="Attendant Categry"></e-grid-column>

                <e-grid-column field="StudentClassification" headerText="Student Classification"></e-grid-column>

                <e-grid-column field="Major" headerText="Major" width="160"></e-grid-column>

                <e-grid-column field="Phone" headerText="Phone"></e-grid-column>

                <e-grid-column field="SignUpDate" headerText="Sign Up Date" customFormat="@(new {type = "datetime", format = "M/d/y hh:mm a" })"></e-grid-column>

                @*<e-grid-column headerText="" template="#template"></e-grid-column>*@

            </e-grid-columns>

        </ejs-grid>


<script>

    function gridCreated() {

        var grid = document.getElementById("Grid").ej2_instances[0];

        grid.hideSpinner = () => true;

        ej.popups.setSpinner({ type: 'Bootstrap' });

        $(".e-spinner-pane").css("display", "block");

    }


    function actionComplete() {

        $(".e-spinner-pane").css("display", "none");

    }


    function actionBegin() {

        $(".e-spinner-pane").css("display", "block");

    }


    document.getElementById('clear').addEventListener('click', () => {

        var gridObj = document.getElementById("Grid").ej2_instances[0];

        gridObj.searchSettings.key = '';

    });

</script>


The steps that I followed are in this documentation:

Data Binding in ASP.NET Core Grid control - Syncfusion

I hope I answered your questions.


Thanks again for your help


Regards



AM Ahmed Mohammedali July 23, 2021 02:33 AM UTC

I also want to mention that I am using the package Google.Cloud.Firestore. Here is the official link:  Google.Cloud.Firestore | Google.Cloud.Firestore (googleapis.dev). I think in this case I cannot use IQueryable, right?



MS Manivel Sellamuthu Syncfusion Team July 27, 2021 04:50 PM UTC

Hi Ahmed, 

The UrlAdaptor works on On-Demand, that helps us to improve the performance for large data application. Using this you can supply the records for current page only(10 records).While paging grid will request an AJAX POST for data to the server with the parameters of Skip and Take. You can use Dataoperations and DataManagerRequest or using your own logic you can process grid actions such as Paging, Sorting, Searching, and Filtering for the server-side actions and need to return the response as Object of result and count format. Please find the below code example screenshots for more information. 

    <div class="row"> 
        <ejs-grid id="job_listing_grid" toolbar="@(new List<string>() {"Search" })"  allowPaging="true" allowSorting="true" allowFiltering="true"> 
            <e-data-manager url="/Home/UrlDataSource" adaptor="UrlAdaptor"></e-data-manager> 
            <e-grid-filterSettings type="Menu"></e-grid-filterSettings> 
            <e-grid-columns> 
                <e-grid-column field="OrderID" headerText="Order ID" isPrimaryKey="true" textAlign="Right" width="100"></e-grid-column> 
                <e-grid-column field="CustomerID" headerText="Customer ID" type="string" width="120"></e-grid-column> 
                <e-grid-column field="ShipCountry" headerText="Ship Country" width="150"></e-grid-column> 
                <e-grid-column field="Freight" width="150"></e-grid-column> 
                <e-grid-column field="IsClose" width="120" displayAsCheckBox="true" textAlign="Left"></e-grid-column> 
            </e-grid-columns> 
        </ejs-grid> 
    </div> 

For initial rendering and paging: 

Grid will request the server with the corresponding skip and take values contains the information for number of records need to be returned from the server.  
 
 
 
While performing sorting: 
 
Grid will request the server with sorting columns information along with the paging details. 

 

While performing searching: 
 
Grid will request the server with searching information information along with the paging details. 
 
 

While performing Filtering:  
 
Grid will request the server with filtering information along with the paging details. 
 
 


If you are using the API calls to perform Grid action from the server, we suggest you to use custom binding approach to bind data in the Grid. With this you can bind data from an API call by providing your own custom queries(as required by your API) and handle all the Grid actions(Sort, Page, Filter, etc. ) with it. The Grid’s custom binding approach is explained below, 

For using custom binding, you need to bind the response data(Grid data) returned from your API as an object of result(JSON data source) and count(Total data count) properties and set it to the Grid’s dataSource property. On setting the data source in this format, the ‘dataStateChange’ event will be triggered with corresponding query for every Grid action performed like Paging, Sorting and Filtering..etc. Using this you can send the queries in your required format to your API, process and return the result and then assign the returned result to the Grid’s dataSource property as an object of result and count properties. Please find the below code example, screenshots for more information. 

@{ 
    ViewData["Title"] = "Home Page"; 
} 
 
    <div class="row"> 
        <ejs-grid id="job_listing_grid" toolbar="@(new List<string>() {"Search" })" allowPaging="true" dataStateChange="dataStateChange" created="created" allowSorting="true" allowFiltering="true"> 
            <e-grid-filterSettings type="Menu"></e-grid-filterSettings> 
            <e-grid-columns> 
                 . . . 
            </e-grid-columns> 
        </ejs-grid> 
    </div> 
 
    <script> 
        var grid; 
      function getData(gridquery) { 
. . . 
    // based on the grid query we have form the url and get the result you can generate query based on your service 
    var ajax = new ej.base.Ajax( 
. . .    ); 
    ajax.send(); 
    ajax.onSuccess = data => { 
      if (grid.element !== undefined) { 
        var final = JSON.parse(data); 
        // finally return the value as result(JSON Object) and count(total count) pair 
        grid.dataSource = { result: final.value, count: final.count }; 
      } 
    }; 
  } 
  function dataStateChange(state) { 
    // get grid queries from the Grid action 
    getData(state);  // trigger for every grid action (page, sort, ect.,) 
  } 
 
        function created() { 
            grid = this; 
      var state = { skip: 0, take: 10 }; 
      getData(state);  // for initial grid settings 
  } 
    </script> 

For initial rendering and paging: 

 

While performing sorting: 

 

While performing filtering: 

 

While performing searching: 
 
 

Regards, 
Manivel 



AM Ahmed Mohammedali August 1, 2021 12:11 AM UTC

Hi,


Thank you for your reply. I am familiar with what you explained above. I hope you help me with pagination with firestore. Specifically, what the equivalent of these lines will be:

if (dm.Skip != 0)

{

DataSource = operation.PerformSkip(DataSource, dm.Skip); //Paging

}

if (dm.Take != 0)

{

DataSource = operation.PerformTake(DataSource, dm.Take);

}


As this works for MSSQL and EntityFramework without problems, it does not work with firestore. This is the problem here.


Thank you



MS Manivel Sellamuthu Syncfusion Team August 2, 2021 12:35 PM UTC

Hi Ahmed, 

Thanks for your update. 

The performSkip and performTake methods of the DataOperations class are used to perform the paging operations for List and SQL Data only. For the fire store(custom service) data you need to manually perform the paging operation based on the skip and take values from the DataManagerRequest. To perform paging in the fire store we suggest you to refer the below general link. 


Regards, 
Manivel 


Loader.
Up arrow icon