[Fixed] How to handle the data returned from the backend (nodejs) to make pagination work in react-admin

Issue

I have problem with pagination in react-admin, you can take a look over here: https://i.stack.imgur.com/KWw5Q.gif
the pagination always show the same records i mean all records at once.

—my backend —- :

const express = require('express')
const app = express()
const port = 5000
var MongoClient = require("mongodb").MongoClient;
const { ObjectId } = require("mongodb"); // or ObjectID
var url = "mongodb://localhost:27017/storedz";
var db;
var storedz;


app.use(function (req, res, next) {
  res.header("Access-Control-Allow-Origin", req.header("Origin"));
  res.header("Access-Control-Allow-Credentials", true);
  res.header(
    "Access-Control-Allow-Headers",
    "Origin, X-Requested-With, Content-Type, Accept"
  );

  res.header("Access-Control-Expose-Headers", "Content-Range");
  res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS, PUT, DELETE");
  next();
});



MongoClient.connect(url, function (err, database) {
    if (err) throw err;
    db = database;
    storedz = db.db("storedz");
  });



app.get('/Products',(req, res) => {
  storedz
    .collection("products")
    .find({})
    .toArray((err, result) => {
      if (err) {
        return res.header(400).json("something went wrong");
      }
      res.header("Content-Range", `Products 1-${result.length}/${result.length}`);
      console.log(result.length)
      res.json(result);
    });

  })

app.listen(port, () => {
  console.log(`Example app listening at http://localhost:${port}`)
})

and this the dataprovider :

import { fetchUtils } from 'react-admin';
import { stringify } from 'query-string';

const apiUrl = 'http://localhost:5000';
const httpClient = fetchUtils.fetchJson;

export default {
    getList: (resource, params) => {
        const { page, perPage } = params.pagination;
        const { field, order } = params.sort;
        const query = {
            sort: JSON.stringify([field, order]),
            range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
            filter: JSON.stringify(params.filter),
        };
        const url = `${apiUrl}/${resource}?${stringify(query)}`;
     
        return httpClient(url).then(({ headers, json }) => ({
            data: json.map((resource)=>({...resource, id:resource._id})),
            total: parseInt(headers.get('content-range').split('/').pop(), 10),
        }));
    },

    getOne: (resource, params) =>
        httpClient(`${apiUrl}/${resource}/${params.id}`).then(({ json }) => ({
             ...json, id: json._id ,
        })),

    getMany: (resource, params) => {
        const query = {
            filter: JSON.stringify({ id: params.ids }),
        };
        const url = `${apiUrl}/${resource}?${stringify(query)}`;
        return httpClient(url).then(({ json }) => ({
            data: json.map(resource => ({ ...resource, id: resource._id }) )
             }));
    },

    getManyReference: (resource, params) => {
        const { page, perPage } = params.pagination;
        const { field, order } = params.sort;
        const query = {
            sort: JSON.stringify([field, order]),
            range: JSON.stringify([(page - 1) * perPage, page * perPage - 1]),
            filter: JSON.stringify({
                ...params.filter,
                [params.target]: params.id,
            }),
        };
        const url = `${apiUrl}/${resource}?${stringify(query)}`;

        return httpClient(url).then(({ headers, json }) => ({
            data: json,
            total: parseInt(headers.get('content-range').split('/').pop(), 10),
        }));
    },

    update: (resource, params) =>
        httpClient(`${apiUrl}/${resource}/${params.id}`, {
            method: 'PUT',
            body: JSON.stringify(params.data),
        }).then(({ json }) => ({ ...json, id: json._id })),

    updateMany: (resource, params) => {
        const query = {
            filter: JSON.stringify({ id: params.ids}),
        };
        return httpClient(`${apiUrl}/${resource}?${stringify(query)}`, {
            method: 'PUT',
            body: JSON.stringify(params.data),
        }).then(({ json }) => ({ data: json }));
    },

    create: (resource, params) =>
        httpClient(`${apiUrl}/${resource}`, {
            method: 'POST',
            body: JSON.stringify(params.data),
        }).then(({ json }) => ({
            data: { ...params.data, id: json.id },
        })),

    delete: (resource, params) =>
        httpClient(`${apiUrl}/${resource}/${params.id}`, {
            method: 'DELETE',
        }).then(({ json }) => ({ data: json })),

    deleteMany: (resource, params) => {
        const query = {
            filter: JSON.stringify({ id: params.ids}),
        };
        return httpClient(`${apiUrl}/${resource}?${stringify(query)}`, {
            method: 'DELETE',
        }).then(({ json }) => ({ data: json }));
    }
};

and this App.js:

import * as React from "react";
import { Admin, Resource  } from 'react-admin';
import  dataProvider  from './DataProvider'
import { Products } from "./Products";
const App=()=> {

  return (
    <div className="App">
<Admin  dataProvider={dataProvider}>
<Resource name='Products' list={Products} />
  </Admin>
    </div>
  );
}

export default App;

I don’t know how to fix issues i spent two days working on it but can’t fix it.
pleas if my question not clear i will update as possible.

Solution

It seems like you are sending the required parameters to your backend (i.e. range), however, you don’t seem to be doing anything with those parameters in the backend. You have to use them to tell mongoDB that it should perform a pagination.

One way to do pagination in mongoDB is to use the skip(<number>) (docs) and limit(<number>) (docs) functions of the API. If you want to use those, it might make more sense that instead of sending the range query parameter, you send a pageSize and an offset parameter to the backend. The pageSize will be simply your perPage value, the offset would be computed by multiplying page with perPage.

Then, in your backend you will need to retrieve those parameters from the query object. You can do so by

const { offset, pageSize } = req.query;

However, be aware that those parameters will be string values, so you want to parse them to numbers before passing them as parameters to the skip and limit function.

Leave a Reply

(*) Required, Your email will not be published