Как получить реальное количество совпадающих документов при использовании limit в mongodb?

#mongodb

Вопрос:

У меня есть агрегация фасетов в mongodb. Это работает. Теперь мне нужно ограничить результат, чтобы получить бесконечный свиток. Как получить общее количество совпадающих документов во всей коллекции?

Я могу получить общее количество документов в коллекции, но это число не имеет значения. Моя цель-узнать, может ли пользователь получить больше данных. Если он получил 120 документов, но 150 соответствуют его фильтру, то можно выполнить другой запрос.

Вот мой вопрос:

 db.collection.aggregate([
  {
    $facet: {
      data: [
        { $match: { score: {$gt: 80 } } },
        { $skip: 0},
        { $limit: 2},
        { $project: { score: 1 } }
      ],
    }
  },
]) 

Вы можете играть с поддельными данными в этой песочнице: https://mongoplayground.net/p/EClbe0f_Fms

Реальное количество совпадающих документов равно 4. Если я добавлю «хиты» после фасета с оператором $count, я получу 7, что составляет общее количество документов. Как эффективно получить эту информацию?

Ответ №1:

Наиболее эффективным способом было бы вообще не использовать $count, а скорее проверить, была ли последняя полученная страница меньше лимита. То есть:

 const perPage = 10;
const results = await getPageOfResults();
const atEnd = results.length < perPage;
 

Похоже, вы уже добавили $count в свой фасет, но получили неверный результат. Чтобы получить «реальное» количество совпадающих документов, вам нужно добавить этап $match к обоим аспектам, например https://mongoplayground.net/p/liQaiyZhYER

 db.collection.aggregate([
  {
    $facet: {
      data: [
        { $match: { score: {$gt: 80 } } },
        { $skip: 0},
        { $limit: 2},
        { $project: { score: 1 } }
      ],
      count: [
        { $match: { score: {$gt: 80 } } },
        { $count: 'total' } 
      ]
    }
  },
  {$unwind: "$count"},
  {$addFields: {
     count: "$count.total"
  }}
])
 

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

1. Хорошо, спасибо за вашу проницательность! В конце концов, я думаю, что просто сделаю два отдельных запроса: один, чтобы получить общую сумму, а затем запрос. Таким образом, общая сумма будет рассчитана только один раз, и я проверю эту информацию в интерфейсе.