Разбивка на основе курсора может быть реализована с использованием любого поля в коллекции, которое является Уникальным, Заказным и Неизменным .
_id
удовлетворяет всем уникальным, заказным и неизменным условиям. На основании этого поля мы можем отсортировать и вернуть результат страницы с _id
последнего документа в качестве последовательности для последующего запроса.
curl https://api.mixmax.com/items?limit=2
const items = db.items.find({}).sort({
_id: -1
}).limit(2);
const next = items[items.length - 1]._id
res.json({ items, next })
, когда пользователь хочет получить вторую страницу, он передает курсор (как следующий) на URL: curl https://api.mixmax.com/items?limit=2&next=590e9abd4abbf1165862d342
const items = db.items.find({
_id: { $lt: req.query.next }
}).sort({
_id: -1
}).limit(2);
const next = items[items.length - 1]._id
res.json({ items, next })
Если мы хотим вернуть результаты в другом порядке, например, в дате элемента, мы добавим sort=launchDate
к строке запроса. curl https://api.mixmax.com/items?limit=2&sort=launchDate
const items = db.items.find({}).sort({
launchDate: -1
}).limit(2);
const next = items[items.length - 1].launchDate;
res.json({ items, next })
Для последующего запроса страницы
curl https://api.mixmax.com/items?limit=2&sort=launchDate&next=2017-09-11T00%3A44%3A54.036Z
const items = db.items.find({
launchDate: { $lt: req.query.next }
}).sort({
_id: -1
}).limit(2);
const next = items[items.length - 1].launchDate;
res.json({ items, next });
Если мы запустили несколько элементов в один и тот же день и время? Теперь наше launchDate
поле больше не является уникальным и не удовлетворяет Уникальным, Заказным и Неизменным . условие. Мы не можем использовать его как поле курсора. Но мы могли бы использовать два поля для генерации курсора. Поскольку мы знаем, что поле _id
в MongoDB всегда удовлетворяет вышеуказанным трем условиям, мы знаем, что если мы используем его вместе с нашим полем launchDate
, комбинация этих двух полей будетудовлетворить требования и могут быть вместе использованы в качестве поля курсора. curl https://api.mixmax.com/items?limit=2&sort=launchDate
const items = db.items.find({}).sort({
launchDate: -1,
_id: -1 // secondary sort in case there are duplicate launchDate values
}).limit(2);
const lastItem = items[items.length - 1];
// The cursor is a concatenation of the two cursor fields, since both are needed to satisfy the requirements of being a cursor field
const next = `${lastItem.launchDate}_${lastItem._id}`;
res.json({ items, next });
Для последующего запроса страницы
curl https://api.mixmax.com/items?limit=2&sort=launchDate&next=2017-09-11T00%3A44%3A54.036Z_590e9abd4abbf1165862d342
const [nextLaunchDate, nextId] = req.query.next.split(‘_’);
const items = db.items.find({
$or: [{
launchDate: { $lt: nextLaunchDate }
}, {
// If the launchDate is an exact match, we need a tiebreaker, so we use the _id field from the cursor.
launchDate: nextLaunchDate,
_id: { $lt: nextId }
}]
}).sort({
_id: -1
}).limit(2);
const lastItem = items[items.length - 1];
// The cursor is a concatenation of the two cursor fields, since both are needed to satisfy the requirements of being a cursor field
const next = `${lastItem.launchDate}_${lastItem._id}`;
res.json({ items, next });
Ссылка: https://engineering.mixmax.com/blog/api-paging-built-the-right-way/