Sequelizeでページングを実装する

ページングの実装

よくあるページングの実装を実装してみました。DB内にはid500までの500レコード入っています。今回はMySQLを使います。 発行されるSQLは LIMIT 0, 10 となっていますが、 LIMIT 10 OFFSET 0 と同じ意味です。

findAllの引数にlimitとoffsetを指定してページングをしています。orderも指定するようにしましょう。

const PAGE_NUM = 10;
const getUsers = (page)=>{
  return new Promise((resolve, reject)=>{
    db.User.findAll({
      limit: PAGE_NUM,
      offset: PAGE_NUM * page,
      order: [['id', 'ASC']],
      raw: true
    }).then((users)=>{
      db.sequelize.close();
      resolve({users: users});
    }).catch((error)=>{
      db.sequelize.close();
      reject(error);
    })
  });
}

getUsers(0).then((users)=>{
    console.log(users);
});

最初のページ

SELECT `id`, `name`, `createdAt`, `updatedAt` 
    FROM `Users` AS `User`
    ORDER BY `User`.`id` ASC
    LIMIT 0, 10;
{ users:
   [ { id: 1,
       name: 'name-1',
       createdAt: 2018-03-23T15:18:49.000Z,
       updatedAt: 2018-03-23T15:18:49.000Z },
     { id: 2,
       name: 'name-33',
       createdAt: 2018-03-23T15:18:49.000Z,
       updatedAt: 2018-03-23T15:18:49.000Z },

       ・
       ・
       ・

     { id: 10,
       name: 'name-36',
       createdAt: 2018-03-23T15:18:50.000Z,
       updatedAt: 2018-03-23T15:18:50.000Z } ] }

最後のページ

SELECT `id`, `name`, `createdAt`, `updatedAt`
    FROM `Users` AS `User`
    ORDER BY `User`.`id` ASC
    LIMIT 490, 10;
{ users:
   [ { id: 491,
       name: 'name-38',
       createdAt: 2018-03-24T03:12:18.000Z,
       updatedAt: 2018-03-24T03:12:18.000Z },
     { id: 492,
       name: 'name-39',
       createdAt: 2018-03-24T03:12:18.000Z,
       updatedAt: 2018-03-24T03:12:18.000Z },

       ・
       ・
       ・

     { id: 500,
       name: 'name-30',
       createdAt: 2018-03-24T03:12:18.000Z,
       updatedAt: 2018-03-24T03:12:18.000Z } ] }

次のページが存在するかの情報も返す場合

APIなどで次のページがあるのかフラグを渡す場合

方針としては 1ページの要素数+1個 をLIMITで取得して 1ページの要素数+1個 返ってきたらtrue、それよりも少なければfalseにします。

また、返すデータとしてはsliceで1ページの要素数分のみ返すようにします。

const PAGE_NUM = 10;
const getUsers = (page)=>{
  return new Promise((resolve, reject)=>{
    db.User.findAll({
      limit: PAGE_NUM + 1,
      offset: PAGE_NUM * page,
      order: [['id', 'ASC']],
      raw: true
    }).then((users)=>{
      db.sequelize.close();
      resolve({users: users.slice(0, PAGE_NUM), nextPage: users.length > PAGE_NUM});
    }).catch((error)=>{
      db.sequelize.close();
      reject(error);
    })
  });
}

getUsers(0).then((users)=>{
    console.log(users);
});

最初のページ

getUsersに0を指定した時です。

SELECT `id`, `name`, `createdAt`, `updatedAt`
    FROM `Users` AS `User` 
    ORDER BY `User`.`id` ASC 
    LIMIT 0, 11;
{ users:
   [ { id: 1,
       name: 'name-1',
       createdAt: 2018-03-23T15:18:49.000Z,
       updatedAt: 2018-03-23T15:18:49.000Z },
     { id: 2,
       name: 'name-33',
       createdAt: 2018-03-23T15:18:49.000Z,
       updatedAt: 2018-03-23T15:18:49.000Z },

       ・
       ・
       ・

     { id: 10,
       name: 'name-36',
       createdAt: 2018-03-23T15:18:50.000Z,
       updatedAt: 2018-03-23T15:18:50.000Z } ],
  nextPage: true }

最後のページ

getUsersに49を指定した時です。ちゃんとnextPageの値がfalseになっています。

SELECT `id`, `name`, `createdAt`, `updatedAt` FROM `Users` AS `User` ORDER BY `User`.`id` ASC LIMIT 490, 11;
{ users:
   [ { id: 491,
       name: 'name-38',
       createdAt: 2018-03-24T03:12:18.000Z,
       updatedAt: 2018-03-24T03:12:18.000Z },
     { id: 492,
       name: 'name-39',
       createdAt: 2018-03-24T03:12:18.000Z,
       updatedAt: 2018-03-24T03:12:18.000Z },

       ・
       ・
       ・

     { id: 500,
       name: 'name-30',
       createdAt: 2018-03-24T03:12:18.000Z,
       updatedAt: 2018-03-24T03:12:18.000Z } ],
  nextPage: false }