count_documents.ts 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. import type { Document } from '../bson';
  2. import type { Collection } from '../collection';
  3. import type { Server } from '../sdam/server';
  4. import type { ClientSession } from '../sessions';
  5. import type { Callback } from '../utils';
  6. import { AggregateOperation, type AggregateOptions } from './aggregate';
  7. /** @public */
  8. export interface CountDocumentsOptions extends AggregateOptions {
  9. /** The number of documents to skip. */
  10. skip?: number;
  11. /** The maximum amounts to count before aborting. */
  12. limit?: number;
  13. }
  14. /** @internal */
  15. export class CountDocumentsOperation extends AggregateOperation<number> {
  16. constructor(collection: Collection, query: Document, options: CountDocumentsOptions) {
  17. const pipeline = [];
  18. pipeline.push({ $match: query });
  19. if (typeof options.skip === 'number') {
  20. pipeline.push({ $skip: options.skip });
  21. }
  22. if (typeof options.limit === 'number') {
  23. pipeline.push({ $limit: options.limit });
  24. }
  25. pipeline.push({ $group: { _id: 1, n: { $sum: 1 } } });
  26. super(collection.s.namespace, pipeline, options);
  27. }
  28. override executeCallback(
  29. server: Server,
  30. session: ClientSession | undefined,
  31. callback: Callback<number>
  32. ): void {
  33. super.executeCallback(server, session, (err, result) => {
  34. if (err || !result) {
  35. callback(err);
  36. return;
  37. }
  38. // NOTE: We're avoiding creating a cursor here to reduce the callstack.
  39. const response = result as unknown as Document;
  40. if (response.cursor == null || response.cursor.firstBatch == null) {
  41. callback(undefined, 0);
  42. return;
  43. }
  44. const docs = response.cursor.firstBatch;
  45. callback(undefined, docs.length ? docs[0].n : 0);
  46. });
  47. }
  48. }