API-интерфейс Node.js с Express & MySQL - получение количества записей, номера страницы и т. Д.

0

Я хотел бы получить и предоставить общее количество total_record_count, page_number, page_size, total_pages, has_more информации в ответе и возможность разбивать на страницы результат, так как я LIMIT запрос до 100. Какой лучший способ сделать это?

Что моя текущая установка:

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});
        }
    );
});

В URL-адресе я хотел бы предоставить/разрешить параметр страницы "p", если total_record_count превышает значение LIMIT. Таким образом, параметр запроса p указывает, какую страницу нужно вернуть, начиная с 1. Если параметр p опущен, значение по умолчанию равно 1. Sth like:

http://localhost:4001/api/v1/users/?active=0&title=mr&p=1
Теги:
express

2 ответа

1

MySQL LIMIT принимает 2 значения, offset & rowcount. Манипулирование ими заключается в том, как вы, конечно, можете сделать пейджинг.

например. Если сказать, что на каждой странице было 10 записей. Page1 = LIMIT 0, 10 Page2 = LIMIT 10, 10 Page3 = LIMIT 20, 10 и т.д.

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

Теперь одна проблема с использованием лимита заключается в том, что учетная запись для набора результатов, IOW: ограниченные 10 записей.

Но то, что вы можете сделать, это попросить MySQL хранить то, что было бы в записи, если бы LIMIT не был применен. Вы можете получить это путем префикса SQL с помощью SQL_CALC_FOUND_ROWS.

например. SELECT SQL_CALC_FOUND_ROWS * FROM TABLE WHERE something LIMIT 10, 10

Затем вы можете выполнить другой запрос, который извлекает это значение.

SELECT FOUND_ROWS();

1

Для разбивки на страницы вам нужен запрос, похожий ниже в MySQL

SELECT * FROM users LIMIT 0,10

С двумя аргументами первый аргумент указывает смещение первой строки для возврата, а второй указывает максимальное количество возвращаемых строк. Смещение начальной строки равно 0 (не 1).

Поскольку вы хотите иметь значение по умолчанию как 1-ю страницу и 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}';
    ...
});

и для вашего второго вопроса о предоставлении общего количества строк вам нужно запустить для этого два запроса. Вы можете использовать SQL_CALC_FOUND_ROWS и FOUND_ROWS() в mysql> 4.0. Но когда у нас есть соответствующие индексы для предложения WHERE/ORDER в нашем запросе, гораздо быстрее использовать два отдельных запроса вместо одного с SQL_CALC_FOUND_ROWS (один для данных и один для получения всего количества строк).

Теперь вы должны запускать оба запроса параллельно для производительности, поэтому с обратным вызовом вы можете использовать эту функцию, которую я написал для параллельного выполнения обратного вызова, и дождаться завершения всех обратных вызовов. Или вы можете использовать многообещающую библиотеку MySQL здесь, или вы можете сделать вашу текущую библиотеку обещанной с помощью Bluebird.

Как это:

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

а затем выполните запрос, подобный этому

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
})

Или вы также можете запустить следующий запрос, который также будет работать

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

Кроме того, вы можете использовать ORM, например, Sequilize или Waterline. Это сделало бы как минимум 10x для MYSQL.

как пример в sequilize:

User.findAndCountAll({
    where: {
        title: {
          [Op.like]: 'ridham'
        }
    },
    offset: 10,
    limit: 2
})
.then(result => {
    console.log(result.count);
    console.log(result.rows);
});
  • 0
    But if you are having WHERE and/or Order clause it's much better to run two queries Почему вы хотите выполнить запрос дважды?, И в идеале счетчик записей должен включать часть WHERE, иначе разбиение по страницам не имеет смысла. например. Допустим, таблица содержит 1000 записей, у этого пользователя есть доступ к 500 по соображениям безопасности / фильтрации и т. д., поэтому у вас есть предложение where, Общее количество страниц должно быть 500/100 = 5, а не 1000/100 = 10; Таким образом, SELECT COUNT(*) FROM table будет давать неверный результат.
  • 0
    Если у вас есть ограниченный результат, вы всегда можете добавить условия для подсчета запросов. percona.com/blog/2007/08/28/… Редактирование ответа.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню