Подтвердить что ты не робот

Ограничить результаты в MongoDB, но все равно получить полный счет?

Для скорости я хотел бы ограничить запрос до 10 результатов

db.collection.find( ... ).limit(10)

Однако я также хотел бы узнать общее количество, так сказать "было 124, но у меня всего 10". Есть ли эффективный способ сделать это?

4b9b3361

Ответ 1

По умолчанию count() игнорирует limit() и подсчитывает результаты всего запроса. Поэтому, когда вы, например, делаете это, var a = db.collection.find(...).limit(10); запуск a.count() даст вам общее количество вашего запроса.

Ответ 2

Ведение счета (1) включает ограничение и пропустить.

Ответ 4

Принятый ответ by @johnnycrab предназначен для CLI монго.

Если вам нужно написать тот же код в Node.js и Express.js, вам придется использовать его так, чтобы использовать функцию "count" вместе с результатом "toArray".

var curFind = db.collection('tasks').find({query});

Затем вы можете запускать две функции после нее (одна вложенная в другую)

curFind.count(function (e, count) {

// Use count here

    curFind.skip(0).limit(10).toArray(function(err, result) {

    // Use result here and count here

    });

});

Ответ 5

Существует решение с использованием push и slice: fooobar.com/info/181954/...

I prefe

  • Сначала для фильтрации, а затем группировки по идентификатору, чтобы получить количество фильтрованных элементов. Не фильтруйте здесь, это не нужно.
  • Второй запрос, который фильтрует, сортирует и разбивает страницы.

Решение с нажатием $$ ROOT и использованием $slice работает с ограничением памяти документа 16 МБ для больших коллекций. Кроме того, для больших коллекций два запроса вместе работают быстрее, чем один с нажатием $$ ROOT. Вы можете запускать их параллельно, поэтому вы ограничены только медленными двумя запросами (возможно, теми, которые сортируются).

Я решил использовать это решение, используя 2 запроса и структуру агрегации (примечание - я использую node.js в этом примере, но идея такая же):

var aggregation = [
  {
    // If you can match fields at the begining, match as many as early as possible.
    $match: {...}
  },
  {
    // Projection.
    $project: {...}
  },
  {
    // Some things you can match only after projection or grouping, so do it now.
    $match: {...}
  }
];


// Copy filtering elements from the pipeline - this is the same for both counting number of fileter elements and for pagination queries.
var aggregationPaginated = aggregation.slice(0);

// Count filtered elements.
aggregation.push(
  {
    $group: {
      _id: null,
      count: { $sum: 1 }
    }
  }
);

// Sort in pagination query.
aggregationPaginated.push(
  {
    $sort: sorting
  }
);

// Paginate.
aggregationPaginated.push(
  {
    $limit: skip + length
  },
  {
    $skip: skip
  }
);

// I use mongoose.

// Get total count.
model.count(function(errCount, totalCount) {
  // Count filtered.
  model.aggregate(aggregation)
  .allowDiskUse(true)
  .exec(
  function(errFind, documents) {
    if (errFind) {
      // Errors.
      res.status(503);
      return res.json({
        'success': false,
        'response': 'err_counting'
      });
    }
    else {
      // Number of filtered elements.
      var numFiltered = documents[0].count;

      // Filter, sort and pagiante.
      model.request.aggregate(aggregationPaginated)
      .allowDiskUse(true)
      .exec(
        function(errFindP, documentsP) {
          if (errFindP) {
            // Errors.
            res.status(503);
            return res.json({
              'success': false,
              'response': 'err_pagination'
            });
          }
          else {
            return res.json({
              'success': true,
              'recordsTotal': totalCount,
              'recordsFiltered': numFiltered,
              'response': documentsP
            });
          }
      });
    }
  });
});