Монгольский указатель агрегации и подсчет

В соответствии с mongodb node драйверами docs функция aggregate теперь возвращает курсор (от версии 2.6).

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

Я видел, что созданный курсор имеет событие данных (это означает, что он CursorStream?), который, похоже, вызвал ожидаемое количество раз, но если я использую его в сочетании с cursor.get, результаты не будут переданы в функцию обратного вызова.

Можно ли использовать новую функцию курсора для подсчета запроса агрегации?

Изменить код:

В оболочке манго:

> db.SentMessages.find({Type : 'Foo'})
{ "_id" : ObjectId("53ea19af9834184ad6d3675a"), "Name" : "123", "Type" : "Foo" }
{ "_id" : ObjectId("53ea19dd9834184ad6d3675c"), "Name" : "789", "Type" : "Foo" }
{ "_id" : ObjectId("53ea19d29834184ad6d3675b"), "Name" : "456", "Type" : "Foo" }

> db.SentMessages.find({Type : 'Foo'}).count()
3

> db.SentMessages.find({Type : 'Foo'}).limit(1)
{ "_id" : ObjectId("53ea19af9834184ad6d3675a"), "Name" : "123", "Type" : "Foo" }

> db.SentMessages.find({Type : 'Foo'}).limit(1).count();
3

> db.SentMessages.aggregate([ { $match : { Type : 'Foo'}} ])
{ "_id" : ObjectId("53ea19af9834184ad6d3675a"), "Name" : "123", "Type" : "Foo" }
{ "_id" : ObjectId("53ea19dd9834184ad6d3675c"), "Name" : "789", "Type" : "Foo" }
{ "_id" : ObjectId("53ea19d29834184ad6d3675b"), "Name" : "456", "Type" : "Foo" }

> db.SentMessages.aggregate([ { $match : { Type : 'Foo'}} ]).count()
2014-08-12T14:47:12.488+0100 TypeError: Object #<Object> has no method 'count'

> db.SentMessages.aggregate([ { $match : { Type : 'Foo'}} ]).itcount()
3

> db.SentMessages.aggregate([ { $match : { Type : 'Foo'}}, {$limit : 1} ])
{ "_id" : ObjectId("53ea19af9834184ad6d3675a"), "Name" : "123", "Type" : "Foo" }

> db.SentMessages.aggregate([ { $match : { Type : 'Foo'}}, {$limit : 1} ]).itcount()
1

> exit
bye

В Node:

var cursor = collection.aggregate([ { $match : { Type : 'Foo'}}, {$limit : 1} ], { cursor : {}});

cursor.get(function(err, res){
  // res is as expected (1 doc)
});

cursor.count() не существует

cursor.itcount() не существует

Событие на данных существует:

cursor.on('data', function(){
    totalItems++;
});

но при использовании в сочетании с cursor.get функция обратного вызова .get теперь содержит 0 docs

Изменить 2: Возвращаемый курсор выглядит как курсор агрегации, а не один из курсоров, перечисленных в документах

Ответ 1

Это, возможно, заслуживает полного объяснения тем, кто может это искать, поэтому добавляя его для потомства.

В частности, возвращается поток событий для node.js, который эффективно обтекает stream.Readable интерфейс с несколькими удобными методами, A .count() не является одним из них в настоящее время и учитывая, что используемый текущий интерфейс не имеет большого смысла.

Подобно результату, возвращенному из метода .stream(), доступного объектам курсора, "счет" здесь не имеет особого смысла, когда вы рассмотрите реализацию, поскольку она предназначена для обработки как "потока", где в конечном итоге вы достигнете "конца", но в противном случае просто хотите обработать, пока не получите там.

Если вы считаете стандартный "курсор" интерфейс от драйвера, есть веские причины, по которым курсор агрегации не является тем же:

  • Курсоры позволяют выполнять действия "модификатора" перед выполнением. Они попадают в категории .sort(), .limit() и .skip(). Все они фактически имеют директивы-партнеры в структуре агрегации, которые указаны в конвейере. В качестве этапов трубопровода, которые могут появляться "в любом месте", а не просто как опция последующей обработки для простого запроса, это не имеет смысла предлагать такую ​​же обработку "курсора".

  • Другие модификаторы курсора включают специальные функции, такие как .hint(), .min() и .max(), которые являются изменениями в "выборе индекса" и обработке. Хотя они могут быть полезны для конвейера агрегации, в настоящее время нет простого способа включить их в выбор запроса. В основном логика из предыдущей точки переопределяет любую точку использования одного и того же типа интерфейса для "курсора".

Другие соображения - это то, что вы на самом деле хотите сделать с помощью курсора и почему вы "хотите" вернуть. Поскольку курсор обычно является "односторонней поездкой" в том смысле, что они, как правило, обрабатываются только до тех пор, пока не будет достигнута конечная цель и не будут использованы "партии", тогда он делает разумный вывод о том, что "подсчет" на самом деле заканчивается, когда на самом деле "очередь" окончательно исчерпана.

Хотя верно, что на самом деле стандартная реализация "курсора" содержит некоторые трюки, основная причина заключается в том, что это просто расширяет концепцию "мета" данных, поскольку механизм профилирования запросов должен "сканировать" определенное количество документов в порядке для определения того, какие элементы будут возвращены в результате.

Структура агрегации играет с этой концепцией немного. Поскольку не только есть те же результаты, которые были бы обработаны через стандартный профилировщик запросов, но также есть дополнительные этапы. Любой из этих этапов может "модифицировать" полученный "счет", который фактически будет возвращен в "поток", который должен быть обработан.

Опять же, если вы хотите взглянуть на это с академической точки зрения и сказать, что "Конечно, механизм запроса должен хранить" метаданные "для подсчета, но разве мы не можем отслеживать, что изменилось после?". Это был бы справедливый аргумент, а операторы конвейера, такие как $match и $group или $unwind и, возможно, включая $project и новый $redact, все можно считать разумным аргументом в том, что они сохраняют свой собственный след "обработанных документов" на каждом этапе трубопровода и обновляют его в "метаданных", которые могли бы возможно, будет возвращен, чтобы объяснить счетчик результатов полного конвейера.

Последний аргумент разумный, но также подумайте, что в настоящее время реализация концепции "Курсор" для результатов конвейерной сборки является новой концепцией для MongoDB. Можно было бы справедливо утверждать, что все "разумные" ожидания в первой точке проектирования состояли бы в том, что "большинство" результатов объединения документов не было бы размера, ограничивающего ограничения BSON. Но по мере того, как использование расширяется, восприятие изменяется, и все меняется, чтобы адаптироваться.

Таким образом, это "возможно" может быть изменено, но это не так, как оно реализовано "в настоящее время". Хотя .count() в стандартной реализации курсора имеет доступ к "метаданным", где записывается отсканированный номер, любой метод текущей реализации приведет к получению всех результатов курсора, как это делает .itcount() в оболочке.

Обработайте элементы "курсора", подсчитав событие "данные" и испустив что-то (возможно, генератор потока JSON) как "счет" в конце. Для любого варианта использования, который потребует подсчета "вверх-вперед", он все равно не будет использоваться для курсора в любом случае, так как, конечно, результат будет представлять собой целый документ разумного размера.