简体   繁体   English

具有express和mysql的Node.js API-获取记录数,页码等,并提供分页

[英]Node.js API with express & mysql - Getting record count, page number, … & provide pagination

I would like to get and provide the total total_record_count, page_number, page_size, total_pages, has_more information in the response and being able to paginate through the result since I LIMIT the query to 100. What's the best way to do this? 我想在响应中获取并提供total_record_count,page_number,page_size,total_pages,has_more信息,并能够将结果分页,因为我将查询限制为100。最佳方法是什么?

That's my current setup: 那是我当前的设置:

router.get('/?', function(req, res, next) {
    const sql = "SELECT * from users ";
    const existingParams = ["title", "active"].filter(field => req.query[field]);

    if (existingParams.length) {
        sql += " WHERE ";
        sql += existingParams.map(field => `${field} = ?`).join(" AND ");
        sql += " LIMIT 100 ";
    }

    connection.query(
        sql,
        existingParams.map(field => req.query[field]),
        function (error, results, fields) {
            res.json({"status": 200, "error": null, "total_record_count": 604, "page_number": 1, "page_size": 100, "total_pages": 7, "has_more": true, "records": results});
        }
    );
});

In the url I would like to be able to provide/allow a page parameter 'p' if the the total_record_count exceeds the LIMIT. 如果total_record_count超过LIMIT,我希望在url中提供/允许页面参数“ p”。 So the query parameter p specifies which page to return, starting with 1. If the p parameter is omitted, the default value is 1. Sth like: 因此,查询参数p从1开始指定要返回的页面。如果省略p参数,则默认值为1。

http://localhost:4001/api/v1/users/?active=0&title=mr&p=1

MySQL LIMIT takes 2 values, offset & rowcount. MySQL LIMIT接受2个值,即offset和rowcount。 Manipulating these is how you could of course do paging. 处理这些是您当然可以进行分页的方式。

eg. 例如。 If say each page was 10 records long. 如果说每页长10条记录。 Page1 = LIMIT 0, 10 Page2 = LIMIT 10, 10 Page3 = LIMIT 20, 10 etc. Page1 = LIMIT 0, 10 0、10 Page2 = LIMIT 10, 10 Page3 = LIMIT 20, 10 20、10等

IOW: LIMIT (pageNo - 1) * PageSize, PageSize IOW: LIMIT (pageNo - 1) * PageSize, PageSize

Now one issue with using limit is that the recordcount is for the resultset, IOW: the limited 10 records. 现在,使用限制的一个问题是记录数用于结果集IOW:有限的10条记录。

But what you can do is ask MySQL to store what the recordcount would have been if the LIMIT was not applied. 但是,您可以做的是让MySQL存储如果未应用LIMIT则记录数应为多少。 You can retrieve this by prefixing the SQL with SQL_CALC_FOUND_ROWS. 您可以通过在SQL前面加上SQL_CALC_FOUND_ROWS来检索此内容。

eg. 例如。 SELECT SQL_CALC_FOUND_ROWS * FROM TABLE WHERE something LIMIT 10, 10

You can then do another query that retrieves this value. 然后,您可以执行另一个查询来检索此值。

SELECT FOUND_ROWS();

For pagination, you need a query something like below in MySQL 对于分页,您需要在MySQL中查询以下内容

SELECT * FROM users LIMIT 0,10

With two arguments, the first argument specifies the offset of the first row to return, and the second specifies the maximum number of rows to return. 有两个参数,第一个参数指定要返回的第一行的偏移量,第二个参数指定要返回的最大行数。 The offset of the initial row is 0 (not 1). 初始行的偏移量是0(不是1)。

As you want to have default value as 1st page and 100 result 由于您希望将默认值设为第一页并得到100个结果

router.get('/?', function(req, res, next) {
    const sql = "SELECT * from users ";
    const existingParams = ["title", "active"].filter(field => req.query[field]);
    const pageNum = req.query.p || 1;
    const pageSize = req.query.p_size || 100;


    if (existingParams.length) {
        sql += " WHERE ";
        sql += existingParams.map(field => `${field} = ?`).join(" AND ");
    }
    sql += ` LIMIT  ${(pageNum - 1) * PageSize},${PageSize}`;
    ...
});

and for your the second question about providing total row count, you need to run two queries for that. 第二个关于提供总行数的问题,您需要为此运行两个查询。 You can utilize SQL_CALC_FOUND_ROWS and FOUND_ROWS() in mysql>4.0. 您可以在mysql> 4.0中使用SQL_CALC_FOUND_ROWS和FOUND_ROWS() But when we have appropriate indexes for WHERE/ORDER clause in our query, it is much faster to use two separate queries instead of one with SQL_CALC_FOUND_ROWS.(one for data and one for getting all row count). 但是,当我们在查询中为WHERE / ORDER子句提供适当的索引时,使用两个单独的查询而不是使用SQL_CALC_FOUND_ROWS进行查询要快得多(一个用于数据,另一个用于获取所有行数)。

Now you have to run both the queries parallel for performance so with callback you can utilize this function that I have written for running callback in parallel and wait until all callbacks are completed. 现在,您必须并行运行两个查询以提高性能,因此对于回调,您可以利用我编写的用于并行运行回调的此函数 ,并等待所有回调完成。 Or you can use promisified MySQL library here or you can make your current library promisified using Bluebird . 或者,您可以在此处使用承诺的MySQL库,也可以使用Bluebird使当前的库承诺。

Like this: 像这样:

const connection = mysql.createConnection({.....});
global.db  = Bluebird.promisifyAll(connection);
db.queryAsync("SELECT * FROM users")
.then(function(rows){ 
    console.log(rows);
})

and then run the query like this 然后像这样运行查询

Promise.all([
    db.queryAsync("SELECT * FROM users WHERE title='ridham' LIMIT 0,10"), // generated by your code
    db.queryAsync("SELECT COUNT(*) FROM users WHERE title='ridham'")
]).then(([data, count]) => {
        // your logic to send response
})

Or you can also run following query, that would also work 或者您也可以运行以下查询,也可以

SELECT * FROM 'table' JOIN (SELECT COUNT(*) FROM 'table') t2 WHERE title='ridham' LIMIT 0,10")

Also, you can use ORM like Sequilize or Waterline . 此外,您可以使用SequilizeWaterline之类的ORM。 That would make your like 10x easier for MYSQL at least. 那至少会使您的MYSQL轻松10倍。

as example in sequilize: 例如在sequilize中:

User.findAndCountAll({
    where: {
        title: {
          [Op.like]: 'ridham'
        }
    },
    offset: 10,
    limit: 2
})
.then(result => {
    console.log(result.count);
    console.log(result.rows);
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM