Как реализовать Twitter и Facebook API, как нумерация страниц на основе курсора в mongodb в nodejs, используя официальный клиент mongodb? - PullRequest
0 голосов
/ 15 октября 2019

Я пытаюсь реализовать разбиение на страницы , которое не должно отображать дубликаты данных на разных страницах при вставке или удалении данных.

Базовый подход на основе смещения с использованием skip и limit для разбивки на страницы данных дан на этой
Как реализовать разбиение на страницыдля mongodb в node.js, использующем официальный клиент mongodb?

Подход на основе смещения имеет большой недостаток: если список результатов изменяется между вызовами API, индексы будутсдвиг и заставить элемент быть либо возвращенным дважды, либо пропущенным и никогда не возвращенным

Эта проблема демонстрируется в
https://www.sitepoint.com/paginating-real-time-data-cursor-based-pagination/

Основанный на времени подход к нумерации страницбыть немного лучше, потому что результаты больше не пропускаются. Если вы запросите первую страницу, а затем новый элемент будет удален, результаты на второй странице не будут сдвинуты, и все в порядке. Однако у этого подхода есть один существенный недостаток: что делать, если одновременно было создано более одного элемента?

Подходы, основанные на смещении и времени, не настолько совершенны. Поэтому мне нужен способ работы Twitter и API API, который использует курсорный подход, используя nodejs и официальный клиент mongodb ?

1 Ответ

0 голосов
/ 16 октября 2019

Разбивка на основе курсора может быть реализована с использованием любого поля в коллекции, которое является Уникальным, Заказным и Неизменным .

_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/

...