Я хотел бы получить и предоставить общее количество 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
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();
Для разбивки на страницы вам нужен запрос, похожий ниже в 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);
});
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
будет давать неверный результат.