CoolFace
Apppublic

opusdev/vector-similarity-api

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes
collection.ts1315 linesDownload Raw Back to src
1import { type BSONSerializeOptions, type Document, resolveBSONOptions } from './bson';2import type {3  AnyBulkWriteOperation,4  BulkOperationBase,5  BulkWriteOptions,6  BulkWriteResult7} from './bulk/common';8import { OrderedBulkOperation } from './bulk/ordered';9import { UnorderedBulkOperation } from './bulk/unordered';10import { ChangeStream, type ChangeStreamDocument, type ChangeStreamOptions } from './change_stream';11import { AggregationCursor } from './cursor/aggregation_cursor';12import { FindCursor } from './cursor/find_cursor';13import { ListIndexesCursor } from './cursor/list_indexes_cursor';14import {15  ListSearchIndexesCursor,16  type ListSearchIndexesOptions17} from './cursor/list_search_indexes_cursor';18import type { Db } from './db';19import { MongoAPIError, MongoInvalidArgumentError, MongoOperationTimeoutError } from './error';20import { type ExplainCommandOptions, type ExplainVerbosityLike } from './explain';21import type { MongoClient, PkFactory } from './mongo_client';22import type {23  Abortable,24  Filter,25  Flatten,26  OptionalUnlessRequiredId,27  TODO_NODE_3286,28  UpdateFilter,29  WithId,30  WithoutId31} from './mongo_types';32import type { AggregateOptions } from './operations/aggregate';33import { CountOperation, type CountOptions } from './operations/count';34import {35  DeleteManyOperation,36  DeleteOneOperation,37  type DeleteOptions,38  type DeleteResult39} from './operations/delete';40import { DistinctOperation, type DistinctOptions } from './operations/distinct';41import { type DropCollectionOptions } from './operations/drop';42import {43  EstimatedDocumentCountOperation,44  type EstimatedDocumentCountOptions45} from './operations/estimated_document_count';46import { autoConnect, executeOperation } from './operations/execute_operation';47import { type FindOneOptions, type FindOptions } from './operations/find';48import {49  FindOneAndDeleteOperation,50  type FindOneAndDeleteOptions,51  FindOneAndReplaceOperation,52  type FindOneAndReplaceOptions,53  FindOneAndUpdateOperation,54  type FindOneAndUpdateOptions55} from './operations/find_and_modify';56import {57  CreateIndexesOperation,58  type CreateIndexesOptions,59  type DropIndexesOptions,60  DropIndexOperation,61  type IndexDescription,62  type IndexDescriptionCompact,63  type IndexDescriptionInfo,64  type IndexInformationOptions,65  type IndexSpecification,66  type ListIndexesOptions67} from './operations/indexes';68import {69  type InsertManyResult,70  InsertOneOperation,71  type InsertOneOptions,72  type InsertOneResult73} from './operations/insert';74import type { Hint, OperationOptions } from './operations/operation';75import { RenameOperation, type RenameOptions } from './operations/rename';76import {77  CreateSearchIndexesOperation,78  type SearchIndexDescription79} from './operations/search_indexes/create';80import { DropSearchIndexOperation } from './operations/search_indexes/drop';81import { UpdateSearchIndexOperation } from './operations/search_indexes/update';82import {83  ReplaceOneOperation,84  type ReplaceOptions,85  UpdateManyOperation,86  UpdateOneOperation,87  type UpdateOptions,88  type UpdateResult89} from './operations/update';90import { ReadConcern, type ReadConcernLike } from './read_concern';91import { ReadPreference, type ReadPreferenceLike } from './read_preference';92import { type Sort } from './sort';93import {94  DEFAULT_PK_FACTORY,95  MongoDBCollectionNamespace,96  normalizeHintField,97  resolveOptions98} from './utils';99import { WriteConcern, type WriteConcernOptions } from './write_concern';100 101/** @public */102export interface ModifyResult<TSchema = Document> {103  value: WithId<TSchema> | null;104  lastErrorObject?: Document;105  ok: 0 | 1;106}107 108/** @public */109export interface CountDocumentsOptions extends AggregateOptions {110  /** The number of documents to skip. */111  skip?: number;112  /** The maximum amount of documents to consider. */113  limit?: number;114}115 116/** @public */117export interface CollectionOptions extends BSONSerializeOptions, WriteConcernOptions {118  /** Specify a read concern for the collection. (only MongoDB 3.2 or higher supported) */119  readConcern?: ReadConcernLike;120  /** The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST). */121  readPreference?: ReadPreferenceLike;122  /**123   * @experimental124   * Specifies the time an operation will run until it throws a timeout error125   */126  timeoutMS?: number;127}128 129/** @internal */130export interface CollectionPrivate {131  pkFactory: PkFactory;132  db: Db;133  options: any;134  namespace: MongoDBCollectionNamespace;135  readPreference?: ReadPreference;136  bsonOptions: BSONSerializeOptions;137  collectionHint?: Hint;138  readConcern?: ReadConcern;139  writeConcern?: WriteConcern;140}141 142/**143 * The **Collection** class is an internal class that embodies a MongoDB collection144 * allowing for insert/find/update/delete and other command operation on that MongoDB collection.145 *146 * **COLLECTION Cannot directly be instantiated**147 * @public148 *149 * @example150 * ```ts151 * import { MongoClient } from 'mongodb';152 *153 * interface Pet {154 *   name: string;155 *   kind: 'dog' | 'cat' | 'fish';156 * }157 *158 * const client = new MongoClient('mongodb://localhost:27017');159 * const pets = client.db().collection<Pet>('pets');160 *161 * const petCursor = pets.find();162 *163 * for await (const pet of petCursor) {164 *   console.log(`${pet.name} is a ${pet.kind}!`);165 * }166 * ```167 */168export class Collection<TSchema extends Document = Document> {169  /** @internal */170  s: CollectionPrivate;171 172  /** @internal */173  client: MongoClient;174 175  /**176   * Get the database object for the collection.177   */178  readonly db: Db;179 180  /**181   * Create a new Collection instance182   * @internal183   */184  constructor(db: Db, name: string, options?: CollectionOptions) {185    this.db = db;186    // Internal state187    this.s = {188      db,189      options,190      namespace: new MongoDBCollectionNamespace(db.databaseName, name),191      pkFactory: db.options?.pkFactory ?? DEFAULT_PK_FACTORY,192      readPreference: ReadPreference.fromOptions(options),193      bsonOptions: resolveBSONOptions(options, db),194      readConcern: ReadConcern.fromOptions(options),195      writeConcern: WriteConcern.fromOptions(options)196    };197 198    this.client = db.client;199  }200 201  /**202   * The name of the database this collection belongs to203   */204  get dbName(): string {205    return this.s.namespace.db;206  }207 208  /**209   * The name of this collection210   */211  get collectionName(): string {212    return this.s.namespace.collection;213  }214 215  /**216   * The namespace of this collection, in the format `${this.dbName}.${this.collectionName}`217   */218  get namespace(): string {219    return this.fullNamespace.toString();220  }221 222  /**223   *  @internal224   *225   * The `MongoDBNamespace` for the collection.226   */227  get fullNamespace(): MongoDBCollectionNamespace {228    return this.s.namespace;229  }230 231  /**232   * The current readConcern of the collection. If not explicitly defined for233   * this collection, will be inherited from the parent DB234   */235  get readConcern(): ReadConcern | undefined {236    if (this.s.readConcern == null) {237      return this.db.readConcern;238    }239    return this.s.readConcern;240  }241 242  /**243   * The current readPreference of the collection. If not explicitly defined for244   * this collection, will be inherited from the parent DB245   */246  get readPreference(): ReadPreference | undefined {247    if (this.s.readPreference == null) {248      return this.db.readPreference;249    }250 251    return this.s.readPreference;252  }253 254  get bsonOptions(): BSONSerializeOptions {255    return this.s.bsonOptions;256  }257 258  /**259   * The current writeConcern of the collection. If not explicitly defined for260   * this collection, will be inherited from the parent DB261   */262  get writeConcern(): WriteConcern | undefined {263    if (this.s.writeConcern == null) {264      return this.db.writeConcern;265    }266    return this.s.writeConcern;267  }268 269  /** The current index hint for the collection */270  get hint(): Hint | undefined {271    return this.s.collectionHint;272  }273 274  set hint(v: Hint | undefined) {275    this.s.collectionHint = normalizeHintField(v);276  }277 278  public get timeoutMS(): number | undefined {279    return this.s.options.timeoutMS;280  }281 282  /**283   * Inserts a single document into MongoDB. If documents passed in do not contain the **_id** field,284   * one will be added to each of the documents missing it by the driver, mutating the document. This behavior285   * can be overridden by setting the **forceServerObjectId** flag.286   *287   * @param doc - The document to insert288   * @param options - Optional settings for the command289   */290  async insertOne(291    doc: OptionalUnlessRequiredId<TSchema>,292    options?: InsertOneOptions293  ): Promise<InsertOneResult<TSchema>> {294    return await executeOperation(295      this.client,296      new InsertOneOperation(297        this as TODO_NODE_3286,298        doc,299        resolveOptions(this, options)300      ) as TODO_NODE_3286301    );302  }303 304  /**305   * Inserts an array of documents into MongoDB. If documents passed in do not contain the **_id** field,306   * one will be added to each of the documents missing it by the driver, mutating the document. This behavior307   * can be overridden by setting the **forceServerObjectId** flag.308   *309   * @param docs - The documents to insert310   * @param options - Optional settings for the command311   */312  async insertMany(313    docs: ReadonlyArray<OptionalUnlessRequiredId<TSchema>>,314    options?: BulkWriteOptions315  ): Promise<InsertManyResult<TSchema>> {316    if (!Array.isArray(docs)) {317      throw new MongoInvalidArgumentError('Argument "docs" must be an array of documents');318    }319    options = resolveOptions(this, options ?? {});320 321    const acknowledged = WriteConcern.fromOptions(options)?.w !== 0;322 323    try {324      const res = await this.bulkWrite(325        docs.map(doc => ({ insertOne: { document: doc } })),326        options327      );328      return {329        acknowledged,330        insertedCount: res.insertedCount,331        insertedIds: res.insertedIds332      };333    } catch (err) {334      if (err && err.message === 'Operation must be an object with an operation key') {335        throw new MongoInvalidArgumentError(336          'Collection.insertMany() cannot be called with an array that has null/undefined values'337        );338      }339      throw err;340    }341  }342 343  /**344   * Perform a bulkWrite operation without a fluent API345   *346   * Legal operation types are347   * - `insertOne`348   * - `replaceOne`349   * - `updateOne`350   * - `updateMany`351   * - `deleteOne`352   * - `deleteMany`353   *354   * If documents passed in do not contain the **_id** field,355   * one will be added to each of the documents missing it by the driver, mutating the document. This behavior356   * can be overridden by setting the **forceServerObjectId** flag.357   *358   * @param operations - Bulk operations to perform359   * @param options - Optional settings for the command360   * @throws MongoDriverError if operations is not an array361   */362  async bulkWrite(363    operations: ReadonlyArray<AnyBulkWriteOperation<TSchema>>,364    options?: BulkWriteOptions365  ): Promise<BulkWriteResult> {366    if (!Array.isArray(operations)) {367      throw new MongoInvalidArgumentError('Argument "operations" must be an array of documents');368    }369 370    options = resolveOptions(this, options ?? {});371 372    // TODO(NODE-7071): remove once the client doesn't need to be connected to construct373    // bulk operations374    const isConnected = this.client.topology != null;375    if (!isConnected) {376      await autoConnect(this.client);377    }378 379    // Create the bulk operation380    const bulk: BulkOperationBase =381      options.ordered === false382        ? this.initializeUnorderedBulkOp(options)383        : this.initializeOrderedBulkOp(options);384 385    // for each op go through and add to the bulk386    for (const operation of operations) {387      bulk.raw(operation);388    }389 390    // Execute the bulk391    return await bulk.execute({ ...options });392  }393 394  /**395   * Update a single document in a collection396   *397   * The value of `update` can be either:398   * - UpdateFilter<TSchema> - A document that contains update operator expressions,399   * - Document[] - an aggregation pipeline.400   *401   * @param filter - The filter used to select the document to update402   * @param update - The modifications to apply403   * @param options - Optional settings for the command404   */405  async updateOne(406    filter: Filter<TSchema>,407    update: UpdateFilter<TSchema> | Document[],408    options?: UpdateOptions & { sort?: Sort }409  ): Promise<UpdateResult<TSchema>> {410    return await executeOperation(411      this.client,412      new UpdateOneOperation(this.s.namespace, filter, update, resolveOptions(this, options))413    );414  }415 416  /**417   * Replace a document in a collection with another document418   *419   * @param filter - The filter used to select the document to replace420   * @param replacement - The Document that replaces the matching document421   * @param options - Optional settings for the command422   */423  async replaceOne(424    filter: Filter<TSchema>,425    replacement: WithoutId<TSchema>,426    options?: ReplaceOptions427  ): Promise<UpdateResult<TSchema>> {428    return await executeOperation(429      this.client,430      new ReplaceOneOperation(this.s.namespace, filter, replacement, resolveOptions(this, options))431    );432  }433 434  /**435   * Update multiple documents in a collection436   *437   * The value of `update` can be either:438   * - UpdateFilter<TSchema> - A document that contains update operator expressions,439   * - Document[] - an aggregation pipeline.440   *441   * @param filter - The filter used to select the document to update442   * @param update - The modifications to apply443   * @param options - Optional settings for the command444   */445  async updateMany(446    filter: Filter<TSchema>,447    update: UpdateFilter<TSchema> | Document[],448    options?: UpdateOptions449  ): Promise<UpdateResult<TSchema>> {450    return await executeOperation(451      this.client,452      new UpdateManyOperation(this.s.namespace, filter, update, resolveOptions(this, options))453    );454  }455 456  /**457   * Delete a document from a collection458   *459   * @param filter - The filter used to select the document to remove460   * @param options - Optional settings for the command461   */462  async deleteOne(463    filter: Filter<TSchema> = {},464    options: DeleteOptions = {}465  ): Promise<DeleteResult> {466    return await executeOperation(467      this.client,468      new DeleteOneOperation(this.s.namespace, filter, resolveOptions(this, options))469    );470  }471 472  /**473   * Delete multiple documents from a collection474   *475   * @param filter - The filter used to select the documents to remove476   * @param options - Optional settings for the command477   */478  async deleteMany(479    filter: Filter<TSchema> = {},480    options: DeleteOptions = {}481  ): Promise<DeleteResult> {482    return await executeOperation(483      this.client,484      new DeleteManyOperation(this.s.namespace, filter, resolveOptions(this, options))485    );486  }487 488  /**489   * Rename the collection.490   *491   * @remarks492   * This operation does not inherit options from the Db or MongoClient.493   *494   * @param newName - New name of of the collection.495   * @param options - Optional settings for the command496   */497  async rename(newName: string, options?: RenameOptions): Promise<Collection> {498    // Intentionally, we do not inherit options from parent for this operation.499    return await executeOperation(500      this.client,501      new RenameOperation(502        this as TODO_NODE_3286,503        newName,504        resolveOptions(undefined, {505          ...options,506          readPreference: ReadPreference.PRIMARY507        })508      )509    );510  }511 512  /**513   * Drop the collection from the database, removing it permanently. New accesses will create a new collection.514   *515   * @param options - Optional settings for the command516   */517  async drop(options?: DropCollectionOptions): Promise<boolean> {518    return await this.db.dropCollection(this.collectionName, options);519  }520 521  /**522   * Fetches the first document that matches the filter523   *524   * @param filter - Query for find Operation525   * @param options - Optional settings for the command526   */527  async findOne(): Promise<WithId<TSchema> | null>;528  async findOne(filter: Filter<TSchema>): Promise<WithId<TSchema> | null>;529  async findOne(530    filter: Filter<TSchema>,531    options: Omit<FindOneOptions, 'timeoutMode'> & Abortable532  ): Promise<WithId<TSchema> | null>;533 534  // allow an override of the schema.535  async findOne<T = TSchema>(): Promise<T | null>;536  async findOne<T = TSchema>(filter: Filter<TSchema>): Promise<T | null>;537  async findOne<T = TSchema>(538    filter: Filter<TSchema>,539    options?: Omit<FindOneOptions, 'timeoutMode'> & Abortable540  ): Promise<T | null>;541 542  async findOne(543    filter: Filter<TSchema> = {},544    options: Omit<FindOneOptions, 'timeoutMode'> & Abortable = {}545  ): Promise<WithId<TSchema> | null> {546    // Explicitly set the limit to 1 and singleBatch to true for all commands, per the spec.547    // noCursorTimeout must be unset as well as batchSize.548    // See: https://github.com/mongodb/specifications/blob/master/source/crud/crud.md#findone-api-details549    const { batchSize: _batchSize, noCursorTimeout: _noCursorTimeout, ...opts } = options;550    opts.singleBatch = true;551    const cursor = this.find(filter, opts).limit(1);552    const result = await cursor.next();553    await cursor.close();554    return result;555  }556 557  /**558   * Creates a cursor for a filter that can be used to iterate over results from MongoDB559   *560   * @param filter - The filter predicate. If unspecified, then all documents in the collection will match the predicate561   */562  find(): FindCursor<WithId<TSchema>>;563  find(filter: Filter<TSchema>, options?: FindOptions & Abortable): FindCursor<WithId<TSchema>>;564  find<T extends Document>(565    filter: Filter<TSchema>,566    options?: FindOptions & Abortable567  ): FindCursor<T>;568  find(569    filter: Filter<TSchema> = {},570    options: FindOptions & Abortable = {}571  ): FindCursor<WithId<TSchema>> {572    return new FindCursor<WithId<TSchema>>(573      this.client,574      this.s.namespace,575      filter,576      resolveOptions(this, options)577    );578  }579 580  /**581   * Returns the options of the collection.582   *583   * @param options - Optional settings for the command584   */585  async options(options?: OperationOptions): Promise<Document> {586    options = resolveOptions(this, options);587    const [collection] = await this.db588      .listCollections({ name: this.collectionName }, { ...options, nameOnly: false })589      .toArray();590 591    if (collection == null || collection.options == null) {592      throw new MongoAPIError(`collection ${this.namespace} not found`);593    }594 595    return collection.options;596  }597 598  /**599   * Returns if the collection is a capped collection600   *601   * @param options - Optional settings for the command602   */603  async isCapped(options?: OperationOptions): Promise<boolean> {604    const { capped } = await this.options(options);605    return Boolean(capped);606  }607 608  /**609   * Creates an index on the db and collection collection.610   *611   * @param indexSpec - The field name or index specification to create an index for612   * @param options - Optional settings for the command613   *614   * @example615   * ```ts616   * const collection = client.db('foo').collection('bar');617   *618   * await collection.createIndex({ a: 1, b: -1 });619   *620   * // Alternate syntax for { c: 1, d: -1 } that ensures order of indexes621   * await collection.createIndex([ [c, 1], [d, -1] ]);622   *623   * // Equivalent to { e: 1 }624   * await collection.createIndex('e');625   *626   * // Equivalent to { f: 1, g: 1 }627   * await collection.createIndex(['f', 'g'])628   *629   * // Equivalent to { h: 1, i: -1 }630   * await collection.createIndex([ { h: 1 }, { i: -1 } ]);631   *632   * // Equivalent to { j: 1, k: -1, l: 2d }633   * await collection.createIndex(['j', ['k', -1], { l: '2d' }])634   * ```635   */636  async createIndex(637    indexSpec: IndexSpecification,638    options?: CreateIndexesOptions639  ): Promise<string> {640    const indexes = await executeOperation(641      this.client,642      CreateIndexesOperation.fromIndexSpecification(643        this,644        this.collectionName,645        indexSpec,646        resolveOptions(this, options)647      )648    );649 650    return indexes[0];651  }652 653  /**654   * Creates multiple indexes in the collection, this method is only supported for655   * MongoDB 2.6 or higher. Earlier version of MongoDB will throw a command not supported656   * error.657   *658   * **Note**: Unlike {@link Collection#createIndex| createIndex}, this function takes in raw index specifications.659   * Index specifications are defined {@link https://www.mongodb.com/docs/manual/reference/command/createIndexes/| here}.660   *661   * @param indexSpecs - An array of index specifications to be created662   * @param options - Optional settings for the command663   *664   * @example665   * ```ts666   * const collection = client.db('foo').collection('bar');667   * await collection.createIndexes([668   *   // Simple index on field fizz669   *   {670   *     key: { fizz: 1 },671   *   }672   *   // wildcard index673   *   {674   *     key: { '$**': 1 }675   *   },676   *   // named index on darmok and jalad677   *   {678   *     key: { darmok: 1, jalad: -1 }679   *     name: 'tanagra'680   *   }681   * ]);682   * ```683   */684  async createIndexes(685    indexSpecs: IndexDescription[],686    options?: CreateIndexesOptions687  ): Promise<string[]> {688    return await executeOperation(689      this.client,690      CreateIndexesOperation.fromIndexDescriptionArray(691        this,692        this.collectionName,693        indexSpecs,694        resolveOptions(this, { ...options, maxTimeMS: undefined })695      )696    );697  }698 699  /**700   * Drops an index from this collection.701   *702   * @param indexName - Name of the index to drop.703   * @param options - Optional settings for the command704   */705  async dropIndex(indexName: string, options?: DropIndexesOptions): Promise<Document> {706    return await executeOperation(707      this.client,708      new DropIndexOperation(this as TODO_NODE_3286, indexName, {709        ...resolveOptions(this, options),710        readPreference: ReadPreference.primary711      })712    );713  }714 715  /**716   * Drops all indexes from this collection.717   *718   * @param options - Optional settings for the command719   */720  async dropIndexes(options?: DropIndexesOptions): Promise<boolean> {721    try {722      await executeOperation(723        this.client,724        new DropIndexOperation(this as TODO_NODE_3286, '*', resolveOptions(this, options))725      );726      return true;727    } catch (error) {728      // TODO(NODE-6517): Driver should only filter for namespace not found error. Other errors should be thrown.729      if (error instanceof MongoOperationTimeoutError) throw error;730      return false;731    }732  }733 734  /**735   * Get the list of all indexes information for the collection.736   *737   * @param options - Optional settings for the command738   */739  listIndexes(options?: ListIndexesOptions): ListIndexesCursor {740    return new ListIndexesCursor(this as TODO_NODE_3286, resolveOptions(this, options));741  }742 743  /**744   * Checks if one or more indexes exist on the collection, fails on first non-existing index745   *746   * @param indexes - One or more index names to check.747   * @param options - Optional settings for the command748   */749  async indexExists(indexes: string | string[], options?: ListIndexesOptions): Promise<boolean> {750    const indexNames: string[] = Array.isArray(indexes) ? indexes : [indexes];751    const allIndexes: Set<string> = new Set(752      await this.listIndexes(options)753        .map(({ name }) => name)754        .toArray()755    );756    return indexNames.every(name => allIndexes.has(name));757  }758 759  /**760   * Retrieves this collections index info.761   *762   * @param options - Optional settings for the command763   */764  indexInformation(765    options: IndexInformationOptions & { full: true }766  ): Promise<IndexDescriptionInfo[]>;767  indexInformation(768    options: IndexInformationOptions & { full?: false }769  ): Promise<IndexDescriptionCompact>;770  indexInformation(771    options: IndexInformationOptions772  ): Promise<IndexDescriptionCompact | IndexDescriptionInfo[]>;773  indexInformation(): Promise<IndexDescriptionCompact>;774  async indexInformation(775    options?: IndexInformationOptions776  ): Promise<IndexDescriptionCompact | IndexDescriptionInfo[]> {777    return await this.indexes({778      ...options,779      full: options?.full ?? false780    });781  }782 783  /**784   * Gets an estimate of the count of documents in a collection using collection metadata.785   * This will always run a count command on all server versions.786   *787   * due to an oversight in versions 5.0.0-5.0.8 of MongoDB, the count command,788   * which estimatedDocumentCount uses in its implementation, was not included in v1 of789   * the Stable API, and so users of the Stable API with estimatedDocumentCount are790   * recommended to upgrade their server version to 5.0.9+ or set apiStrict: false to avoid791   * encountering errors.792   *793   * @see {@link https://www.mongodb.com/docs/manual/reference/command/count/#behavior|Count: Behavior}794   * @param options - Optional settings for the command795   */796  async estimatedDocumentCount(options?: EstimatedDocumentCountOptions): Promise<number> {797    return await executeOperation(798      this.client,799      new EstimatedDocumentCountOperation(this as TODO_NODE_3286, resolveOptions(this, options))800    );801  }802 803  /**804   * Gets the number of documents matching the filter.805   * For a fast count of the total documents in a collection see {@link Collection#estimatedDocumentCount| estimatedDocumentCount}.806   *807   * Due to countDocuments using the $match aggregation pipeline stage, certain query operators cannot be used in countDocuments. This includes the $where and $near query operators, among others. Details can be found in the documentation for the $match aggregation pipeline stage.808   *809   * **Note**: When migrating from {@link Collection#count| count} to {@link Collection#countDocuments| countDocuments}810   * the following query operators must be replaced:811   *812   * | Operator | Replacement |813   * | -------- | ----------- |814   * | `$where`   | [`$expr`][1] |815   * | `$near`    | [`$geoWithin`][2] with [`$center`][3] |816   * | `$nearSphere` | [`$geoWithin`][2] with [`$centerSphere`][4] |817   *818   * [1]: https://www.mongodb.com/docs/manual/reference/operator/query/expr/819   * [2]: https://www.mongodb.com/docs/manual/reference/operator/query/geoWithin/820   * [3]: https://www.mongodb.com/docs/manual/reference/operator/query/center/#op._S_center821   * [4]: https://www.mongodb.com/docs/manual/reference/operator/query/centerSphere/#op._S_centerSphere822   *823   * @param filter - The filter for the count824   * @param options - Optional settings for the command825   *826   * @see https://www.mongodb.com/docs/manual/reference/operator/query/expr/827   * @see https://www.mongodb.com/docs/manual/reference/operator/query/geoWithin/828   * @see https://www.mongodb.com/docs/manual/reference/operator/query/center/#op._S_center829   * @see https://www.mongodb.com/docs/manual/reference/operator/query/centerSphere/#op._S_centerSphere830   */831  async countDocuments(832    filter: Filter<TSchema> = {},833    options: CountDocumentsOptions & Abortable = {}834  ): Promise<number> {835    const pipeline = [];836    pipeline.push({ $match: filter });837 838    if (typeof options.skip === 'number') {839      pipeline.push({ $skip: options.skip });840    }841 842    if (typeof options.limit === 'number') {843      pipeline.push({ $limit: options.limit });844    }845 846    pipeline.push({ $group: { _id: 1, n: { $sum: 1 } } });847 848    const cursor = this.aggregate<{ n: number }>(pipeline, options);849    const doc = await cursor.next();850    await cursor.close();851    return doc?.n ?? 0;852  }853 854  /**855   * The distinct command returns a list of distinct values for the given key across a collection.856   *857   * @param key - Field of the document to find distinct values for858   * @param filter - The filter for filtering the set of documents to which we apply the distinct filter.859   * @param options - Optional settings for the command860   */861  distinct<Key extends keyof WithId<TSchema>>(862    key: Key863  ): Promise<Array<Flatten<WithId<TSchema>[Key]>>>;864  distinct<Key extends keyof WithId<TSchema>>(865    key: Key,866    filter: Filter<TSchema>867  ): Promise<Array<Flatten<WithId<TSchema>[Key]>>>;868  distinct<Key extends keyof WithId<TSchema>>(869    key: Key,870    filter: Filter<TSchema>,871    options: DistinctOptions872  ): Promise<Array<Flatten<WithId<TSchema>[Key]>>>;873  distinct<Key extends keyof WithId<TSchema>>(874    key: Key,875    filter: Filter<TSchema>,876    options: DistinctOptions & { explain: ExplainVerbosityLike | ExplainCommandOptions }877  ): Promise<Document>;878 879  // Embedded documents overload880  distinct(key: string): Promise<any[]>;881  distinct(key: string, filter: Filter<TSchema>): Promise<any[]>;882  distinct(key: string, filter: Filter<TSchema>, options: DistinctOptions): Promise<any[]>;883 884  async distinct<Key extends keyof WithId<TSchema>>(885    key: Key,886    filter: Filter<TSchema> = {},887    options: DistinctOptions = {}888  ): Promise<any[]> {889    return await executeOperation(890      this.client,891      new DistinctOperation(892        this as TODO_NODE_3286,893        key as TODO_NODE_3286,894        filter,895        resolveOptions(this, options)896      )897    );898  }899 900  /**901   * Retrieve all the indexes on the collection.902   *903   * @param options - Optional settings for the command904   */905  indexes(options: IndexInformationOptions & { full?: true }): Promise<IndexDescriptionInfo[]>;906  indexes(options: IndexInformationOptions & { full: false }): Promise<IndexDescriptionCompact>;907  indexes(908    options: IndexInformationOptions909  ): Promise<IndexDescriptionCompact | IndexDescriptionInfo[]>;910  indexes(options?: ListIndexesOptions): Promise<IndexDescriptionInfo[]>;911  async indexes(912    options?: IndexInformationOptions913  ): Promise<IndexDescriptionCompact | IndexDescriptionInfo[]> {914    const indexes: IndexDescriptionInfo[] = await this.listIndexes(options).toArray();915    const full = options?.full ?? true;916    if (full) {917      return indexes;918    }919 920    const object: IndexDescriptionCompact = Object.fromEntries(921      indexes.map(({ name, key }) => [name, Object.entries(key)])922    );923 924    return object;925  }926 927  /**928   * Find a document and delete it in one atomic operation. Requires a write lock for the duration of the operation.929   *930   * @param filter - The filter used to select the document to remove931   * @param options - Optional settings for the command932   */933  async findOneAndDelete(934    filter: Filter<TSchema>,935    options: FindOneAndDeleteOptions & { includeResultMetadata: true }936  ): Promise<ModifyResult<TSchema>>;937  async findOneAndDelete(938    filter: Filter<TSchema>,939    options: FindOneAndDeleteOptions & { includeResultMetadata: false }940  ): Promise<WithId<TSchema> | null>;941  async findOneAndDelete(942    filter: Filter<TSchema>,943    options: FindOneAndDeleteOptions944  ): Promise<WithId<TSchema> | null>;945  async findOneAndDelete(filter: Filter<TSchema>): Promise<WithId<TSchema> | null>;946  async findOneAndDelete(947    filter: Filter<TSchema>,948    options?: FindOneAndDeleteOptions949  ): Promise<WithId<TSchema> | ModifyResult<TSchema> | null> {950    return await executeOperation(951      this.client,952      new FindOneAndDeleteOperation(953        this as TODO_NODE_3286,954        filter,955        resolveOptions(this, options)956      ) as TODO_NODE_3286957    );958  }959 960  /**961   * Find a document and replace it in one atomic operation. Requires a write lock for the duration of the operation.962   *963   * @param filter - The filter used to select the document to replace964   * @param replacement - The Document that replaces the matching document965   * @param options - Optional settings for the command966   */967  async findOneAndReplace(968    filter: Filter<TSchema>,969    replacement: WithoutId<TSchema>,970    options: FindOneAndReplaceOptions & { includeResultMetadata: true }971  ): Promise<ModifyResult<TSchema>>;972  async findOneAndReplace(973    filter: Filter<TSchema>,974    replacement: WithoutId<TSchema>,975    options: FindOneAndReplaceOptions & { includeResultMetadata: false }976  ): Promise<WithId<TSchema> | null>;977  async findOneAndReplace(978    filter: Filter<TSchema>,979    replacement: WithoutId<TSchema>,980    options: FindOneAndReplaceOptions981  ): Promise<WithId<TSchema> | null>;982  async findOneAndReplace(983    filter: Filter<TSchema>,984    replacement: WithoutId<TSchema>985  ): Promise<WithId<TSchema> | null>;986  async findOneAndReplace(987    filter: Filter<TSchema>,988    replacement: WithoutId<TSchema>,989    options?: FindOneAndReplaceOptions990  ): Promise<WithId<TSchema> | ModifyResult<TSchema> | null> {991    return await executeOperation(992      this.client,993      new FindOneAndReplaceOperation(994        this as TODO_NODE_3286,995        filter,996        replacement,997        resolveOptions(this, options)998      ) as TODO_NODE_3286999    );1000  }1001 1002  /**1003   * Find a document and update it in one atomic operation. Requires a write lock for the duration of the operation.1004   *1005   * The value of `update` can be either:1006   * - UpdateFilter<TSchema> - A document that contains update operator expressions,1007   * - Document[] - an aggregation pipeline consisting of the following stages:1008   *   - $addFields and its alias $set1009   *   - $project and its alias $unset1010   *   - $replaceRoot and its alias $replaceWith.1011   * See the [findAndModify command documentation](https://www.mongodb.com/docs/manual/reference/command/findAndModify) for details.1012   *1013   * @param filter - The filter used to select the document to update1014   * @param update - The modifications to apply1015   * @param options - Optional settings for the command1016   */1017  async findOneAndUpdate(1018    filter: Filter<TSchema>,1019    update: UpdateFilter<TSchema> | Document[],1020    options: FindOneAndUpdateOptions & { includeResultMetadata: true }1021  ): Promise<ModifyResult<TSchema>>;1022  async findOneAndUpdate(1023    filter: Filter<TSchema>,1024    update: UpdateFilter<TSchema> | Document[],1025    options: FindOneAndUpdateOptions & { includeResultMetadata: false }1026  ): Promise<WithId<TSchema> | null>;1027  async findOneAndUpdate(1028    filter: Filter<TSchema>,1029    update: UpdateFilter<TSchema> | Document[],1030    options: FindOneAndUpdateOptions1031  ): Promise<WithId<TSchema> | null>;1032  async findOneAndUpdate(1033    filter: Filter<TSchema>,1034    update: UpdateFilter<TSchema> | Document[]1035  ): Promise<WithId<TSchema> | null>;1036  async findOneAndUpdate(1037    filter: Filter<TSchema>,1038    update: UpdateFilter<TSchema> | Document[],1039    options?: FindOneAndUpdateOptions1040  ): Promise<WithId<TSchema> | ModifyResult<TSchema> | null> {1041    return await executeOperation(1042      this.client,1043      new FindOneAndUpdateOperation(1044        this as TODO_NODE_3286,1045        filter,1046        update,1047        resolveOptions(this, options)1048      ) as TODO_NODE_32861049    );1050  }1051 1052  /**1053   * Execute an aggregation framework pipeline against the collection, needs MongoDB \>= 2.21054   *1055   * @param pipeline - An array of aggregation pipelines to execute1056   * @param options - Optional settings for the command1057   */1058  aggregate<T extends Document = Document>(1059    pipeline: Document[] = [],1060    options?: AggregateOptions & Abortable1061  ): AggregationCursor<T> {1062    if (!Array.isArray(pipeline)) {1063      throw new MongoInvalidArgumentError(1064        'Argument "pipeline" must be an array of aggregation stages'1065      );1066    }1067 1068    return new AggregationCursor(1069      this.client,1070      this.s.namespace,1071      pipeline,1072      resolveOptions(this, options)1073    );1074  }1075 1076  /**1077   * Create a new Change Stream, watching for new changes (insertions, updates, replacements, deletions, and invalidations) in this collection.1078   *1079   * @remarks1080   * watch() accepts two generic arguments for distinct use cases:1081   * - The first is to override the schema that may be defined for this specific collection1082   * - The second is to override the shape of the change stream document entirely, if it is not provided the type will default to ChangeStreamDocument of the first argument1083   * @example1084   * By just providing the first argument I can type the change to be `ChangeStreamDocument<{ _id: number }>`1085   * ```ts1086   * collection.watch<{ _id: number }>()1087   *   .on('change', change => console.log(change._id.toFixed(4)));1088   * ```1089   *1090   * @example1091   * Passing a second argument provides a way to reflect the type changes caused by an advanced pipeline.1092   * Here, we are using a pipeline to have MongoDB filter for insert changes only and add a comment.1093   * No need start from scratch on the ChangeStreamInsertDocument type!1094   * By using an intersection we can save time and ensure defaults remain the same type!1095   * ```ts1096   * collection1097   *   .watch<Schema, ChangeStreamInsertDocument<Schema> & { comment: string }>([1098   *     { $addFields: { comment: 'big changes' } },1099   *     { $match: { operationType: 'insert' } }1100   *   ])1101   *   .on('change', change => {1102   *     change.comment.startsWith('big');1103   *     change.operationType === 'insert';1104   *     // No need to narrow in code because the generics did that for us!1105   *     expectType<Schema>(change.fullDocument);1106   *   });1107   * ```1108   *1109   * @remarks1110   * When `timeoutMS` is configured for a change stream, it will have different behaviour depending1111   * on whether the change stream is in iterator mode or emitter mode. In both cases, a change1112   * stream will time out if it does not receive a change event within `timeoutMS` of the last change1113   * event.1114   *1115   * Note that if a change stream is consistently timing out when watching a collection, database or1116   * client that is being changed, then this may be due to the server timing out before it can finish1117   * processing the existing oplog. To address this, restart the change stream with a higher1118   * `timeoutMS`.1119   *1120   * If the change stream times out the initial aggregate operation to establish the change stream on1121   * the server, then the client will close the change stream. If the getMore calls to the server1122   * time out, then the change stream will be left open, but will throw a MongoOperationTimeoutError1123   * when in iterator mode and emit an error event that returns a MongoOperationTimeoutError in1124   * emitter mode.1125   *1126   * To determine whether or not the change stream is still open following a timeout, check the1127   * {@link ChangeStream.closed} getter.1128   *1129   * @example1130   * In iterator mode, if a next() call throws a timeout error, it will attempt to resume the change stream.1131   * The next call can just be retried after this succeeds.1132   * ```ts1133   * const changeStream = collection.watch([], { timeoutMS: 100 });1134   * try {1135   *     await changeStream.next();1136   * } catch (e) {1137   *     if (e instanceof MongoOperationTimeoutError && !changeStream.closed) {1138   *       await changeStream.next();1139   *     }1140   *     throw e;1141   * }1142   * ```1143   *1144   * @example1145   * In emitter mode, if the change stream goes `timeoutMS` without emitting a change event, it will1146   * emit an error event that returns a MongoOperationTimeoutError, but will not close the change1147   * stream unless the resume attempt fails. There is no need to re-establish change listeners as1148   * this will automatically continue emitting change events once the resume attempt completes.1149   *1150   * ```ts1151   * const changeStream = collection.watch([], { timeoutMS: 100 });1152   * changeStream.on('change', console.log);1153   * changeStream.on('error', e => {1154   *     if (e instanceof MongoOperationTimeoutError && !changeStream.closed) {1155   *         // do nothing1156   *     } else {1157   *         changeStream.close();1158   *     }1159   * });1160   * ```1161   *1162   * @param pipeline - An array of {@link https://www.mongodb.com/docs/manual/reference/operator/aggregation-pipeline/|aggregation pipeline stages} through which to pass change stream documents. This allows for filtering (using $match) and manipulating the change stream documents.1163   * @param options - Optional settings for the command1164   * @typeParam TLocal - Type of the data being detected by the change stream1165   * @typeParam TChange - Type of the whole change stream document emitted1166   */1167  watch<TLocal extends Document = TSchema, TChange extends Document = ChangeStreamDocument<TLocal>>(1168    pipeline: Document[] = [],1169    options: ChangeStreamOptions = {}1170  ): ChangeStream<TLocal, TChange> {1171    // Allow optionally not specifying a pipeline1172    if (!Array.isArray(pipeline)) {1173      options = pipeline;1174      pipeline = [];1175    }1176 1177    return new ChangeStream<TLocal, TChange>(this, pipeline, resolveOptions(this, options));1178  }1179 1180  /**1181   * Initiate an Out of order batch write operation. All operations will be buffered into insert/update/remove commands executed out of order.1182   *1183   * @throws MongoNotConnectedError1184   * @remarks1185   * **NOTE:** MongoClient must be connected prior to calling this method due to a known limitation in this legacy implementation.1186   * However, `collection.bulkWrite()` provides an equivalent API that does not require prior connecting.1187   */1188  initializeUnorderedBulkOp(options?: BulkWriteOptions): UnorderedBulkOperation {1189    return new UnorderedBulkOperation(this as TODO_NODE_3286, resolveOptions(this, options));1190  }1191 1192  /**1193   * Initiate an In order bulk write operation. Operations will be serially executed in the order they are added, creating a new operation for each switch in types.1194   *1195   * @throws MongoNotConnectedError1196   * @remarks1197   * **NOTE:** MongoClient must be connected prior to calling this method due to a known limitation in this legacy implementation.1198   * However, `collection.bulkWrite()` provides an equivalent API that does not require prior connecting.1199   */1200  initializeOrderedBulkOp(options?: BulkWriteOptions): OrderedBulkOperation {

Showing the first 1,200 of 1315 lines. Download the file for the rest.