пятница, 14 января 2022 г.

Mongo: Aggregation with Pagination

Допустим у нас есть такая коллекция users в Mongo DB:
[
  {
    username: "john.doe",
    roles: ["user"],
    contacts: [
      {
        name: "John Doe",
        email: "johndoe@gmail.com"
      },
      {
        name: "J.D.",
        email: "jd@gmail.com",
        phone: "+11111111111"
      }
    ]
  },
  {
    username: "jack.sparrow",
    roles: ["manager"],
    contacts: [
      {
        name: "Jack Sparrow (gmail)",
        email: "jack.sparrow@gmail.com",
      },
      {
        name: "Jack Sparrow (hotmail)",
        email: "jack.sparrow@hotmail.com",
      }
    ]
  }
]

И мы хотим организовать просмотр всех контактов всех пользователей в одной таблице с разбивкой по страницам ("pagination"). То есть так:


Чтобы получить все контакты можно воспользоваться aggregation с $unwind.

Еще нам нужно посчитать количество всех контактов, после чего "вырезать" только те, которые нужно показать в выбранной странице. Для того, чтобы выполнить обе эти операции одним запросом, воспользуемся чудесной пайплайн-стадией $facet. Получится так:
db.collection('users').aggregate([
  {"$unwind":"$contacts"},
  {"$facet":{
    "meta":[
      {"$count": "totalCount"}
    ],
    "data":[
      {"$sort":{'contacts.name':1,'username':1}},
      {"$skip":firstRow-1},
      {"$limit":page_size},
      {"$replaceRoot":
        {"newRoot":{
          "$mergeObjects":[
            {
              "username":"$username",
            },
            "$contacts"
          ]
        }}
      },
    ],
  }},
]);
page_size - это количество записей на странице.
firstRow - это номер первой записи на странице. Вычисляется он так:
const firstRow = (page > 0 ? ((page-1) * page_size) : 0) + 1;
Вместо $unwind могут быть другие пайплайн-стадии, которые выбирают нужные для показа данные. Основной же прием, который я хотел продемонстрировать в этом посте, - это использование $facet.

Полный пример можно посмотреть на github:
===
Перепечатка материалов блога разрешается с обязательной ссылкой на blog.coolsoftware.ru

Комментариев нет:

Отправить комментарий