## Description

`insert()` is a Data manipulation language (DML) stage that adds new documents
to Cloud Firestore. This stage can be attached to the end of a query to
insert the results of that query into a collection.

The `insert()` stage can take different arguments to determine the destination
collection and document ID:

- `insert(collectionName, documentIdExpression)`: Inserts documents into the specified collection, using the evaluated expression to determine the document ID.
- `insert(collectionName)`: Inserts documents into the specified collection, automatically generating document IDs.
- `insert()`: Inserts documents, requiring a `__name__` field in the input document to determine the destination collection and document ID.

## Examples

### Insert static documents

The following example inserts new documents into the `users` collection,
using the `id` field from the input to define the document IDs:

##### Node.js

\`\`\`js const results = await db.pipeline() .literals(\[ { foo: "bar", id: "doc1" }, { foo: "baz", id: "doc2" } \]) .insert({ collection: "users", documentId: field("id") }) .execute(); \`\`\`

##### Java

\`\`\`java Pipeline pipeline = db.pipeline() .literals( Map.of("foo", "bar", "id", "doc1"), Map.of("foo", "baz", "id", "doc2")) .insert(new Insert().withCollection("users").withDocumentId(field("id"))); pipeline.execute(); \`\`\`

## Behavior

The following sections describe the execution behavior, responses, and
restrictions for the `insert()` stage.

### Evaluated Document ID Expression

The following example computes new document IDs using a string concatenation
expression `stringConcat(...)` and inserts the results
into `new_users` inside an explicit transaction:

##### Node.js

\`\`\`js const results = await db.runTransaction(async (transaction) =\> { return transaction.execute( db.pipeline() .collection("users") .distinct(field("name")) .insert({ collection: "new_users", documentId: stringConcat(constant("new_"), field("name")), }) ); }); \`\`\`

##### Java

\`\`\`java Pipeline pipeline = db.pipeline() .collection("users") .distinct(field("name")) .insert(new Insert() .withCollection("new_users") .withDocumentId(stringConcat(constant("new_"), field("name")))); db.runTransaction(transaction -\> { transaction.execute(pipeline); return null; }); \`\`\`

### Document References (`__name__`)

The following example uses document references assigned to the `__name__` field
to specify both destination collection and document ID:

##### Node.js

\`\`\`js const results = await db.pipeline() .literals(\[ { __name__: db.doc("users/doc1"), foo: "bar" }, { __name__: db.doc("users/doc2"), foo: "baz" } \]) .insert() .execute(); \`\`\`

##### Java

\`\`\`java Pipeline pipeline = db.pipeline() .literals( Map.of("__name__", db.document("users/doc1"), "foo", "bar"), Map.of("__name__", db.document("users/doc2"), "foo", "baz")) .insert(new Insert()); pipeline.execute(); \`\`\`

### Auto-Generated IDs

The following example inserts new documents into the `users` collection,
allowing Cloud Firestore to auto-generate the document IDs:

##### Node.js

\`\`\`js const results = await db.pipeline() .literals(\[ { foo: "bar" }, { foo: "baz" } \]) .insert({ collection: "users" }) .execute(); \`\`\`

##### Java

\`\`\`java Pipeline pipeline = db.pipeline() .literals( Map.of("foo", "bar"), Map.of("foo", "baz")) .insert(new Insert().withCollection("users")); pipeline.execute(); \`\`\`

### Insert Into a Subcollection

The `insert()` stage can be used to insert documents directly into a
subcollection using a full path.

##### Node.js

\`\`\`js const results = await db.pipeline() .literals(\[ { title: "post1" }, { title: "post2" } \]) .insert({ collection: "users/u1/posts" }) .execute(); \`\`\`

##### Java

\`\`\`java Pipeline pipeline = db.pipeline() .literals( Map.of("title", "post1"), Map.of("title", "post2")) .insert(new Insert().withCollection("users/u1/posts")); pipeline.execute(); \`\`\`

### Insert Into a Different Collection

The `insert()` stage can read from one collection, apply transformations, and
write into another collection within a transaction:

##### Node.js

\`\`\`js const results = await db.runTransaction(async (transaction) =\> { return transaction.execute( db.pipeline() .collection("source_coll") .where(field("active").equal(true)) .addFields(constant("val").as("new_field")) .insert({ collection: "target_coll" }) ); }); \`\`\`

##### Java

\`\`\`java Pipeline pipeline = db.pipeline() .collection("source_coll") .where(field("active").equal(true)) .addFields(constant("val").as("new_field")) .insert(new Insert().withCollection("target_coll")); db.runTransaction(transaction -\> { transaction.execute(pipeline); return null; }); \`\`\`

### Insert from Advanced Queries (Search and Find Nearest)

The `insert()` stage can be used with advanced query operations like `search` or
`findNearest` to write the matching documents into an output collection.

##### Node.js

\`\`\`js const results = await db.runTransaction(async (transaction) =\> { return transaction.execute( db.pipeline() .collection("products") .search({ query: "shoes" }) .insert({ collection: "matched_products" }) ); }); \`\`\`

##### Java

\`\`\`java Pipeline pipeline = db.pipeline() .collection("products") .search(searchOptionsBuilder().query(documentMatches("shoes"))) .insert(new Insert().withCollection("matched_products")); db.runTransaction(transaction -\> { transaction.execute(pipeline); return null; }); \`\`\`

### Response

The `insert()` stage always emits a single document like
`{ documents_modified: 2 }` describing how many documents were inserted.

### Final Stage

The `insert()` stage must come at the end of a pipeline, no further stages can
be provided.

### Transaction Required

The `insert()` stage requires a transaction. It must be run within an active
read-write transaction, or with the `atomic` (Node.js) or `auto_commit` option
set to true when starting a new transaction.

### Already Exists

The `insert()` stage will fail with an `ALREADY_EXISTS` error if any document to
be inserted already exists in the destination.

### Response

The response includes a summary of the number of documents modified.
For example, the following response confirms that the pipeline modified
three documents:

```javascript
{documents_modified: 3L}
```

### Limitations

- DML stages can now be run within transactions. The `insert()` and `upsert()`
  stages need to be run within a transaction in most cases.

- When executing a pipeline with DML stages within a new transaction, you can
  use the `atomic` option to automatically run
  within a transaction and commit upon successful execution of the pipeline.

- When running within a transaction, there are no restrictions on other stages
  (such as `where`, `addFields`, `union`, `findNearest`, and `aggregate`
  subqueries). Transactional DML operations are bounded by
  Firestore Enterprise edition transaction limits. Because transactions don't
  allow reads after the first write, you cannot call a DML pipeline multiple
  times within a single transaction or read documents after a DML pipeline
  executes. Attempting to execute a read after a DML write fails with a
  `FAILED_PRECONDITION` error:
  `Cannot have reads after the first write in a Firestore transaction.`

- When running outside of a transaction:

  - Each document is updated independently of each other, and writes are not atomic across documents. The pipeline halts on the first error, allowing for partial success to occur.
  - Advanced multi-query stages (`aggregate`, `distinct`, `unnest`, `find_nearest`, `union`, joins, and subqueries) are not supported.
- Under Firebase Security Rules, each batch of documents re-evaluates rules
  and executes lookups. If rules use `get()` or `exists()`, the global 20-lookup
  limit is reached after writing approximately 200 documents, and the operation
  fails with `PERMISSION_DENIED`. Use Custom Claims instead of `get()` / `exists()`
  lookups to avoid this limit.

- If the stage preceding the DML stage produces multiple documents with the
  same `__name__` or evaluates to the same destination document ID, each
  mutation is processed sequentially:

  - For `upsert(...)` and `update(...)`: Multiple mutations targeting the same document follow "last one wins" semantics, where the last mutation processed determines the final state of the document.
  - For `delete(...)`: The first attempt deletes the document, and subsequent attempts for the same document are no-ops.
  - For `insert(...)`: The first attempt creates the document, and subsequent attempts targeting the same document ID fail with an `ALREADY_EXISTS` error.

### Transactional Execution

DML operations can be executed as part of a read-write transaction by either
providing an explicit transaction to the pipeline execution call or by using the
`atomic` option.

Firestore transactions require all reads to execute before any writes. Because
a DML pipeline executes writes, you cannot perform reads (such as document
lookups or query reads) after running a DML pipeline in the same transaction.
For example, you cannot call a DML pipeline multiple times in a single
transaction. Attempting to read after a DML pipeline executes fails with a
`FAILED_PRECONDITION` error:
`Cannot have reads after the first write in a Firestore transaction.`

#### Using an explicit transaction

##### Node.js

\`\`\`js // Execute a pipeline with DML stage within an explicit transaction const pipeline = db.pipeline() .collection("users") .where(field("active").equal(false)) .addFields(constant("inactive").as("status")) .update(); await db.runTransaction(async (transaction) =\> { return transaction.execute(pipeline); }); \`\`\`

##### Java

\`\`\`java // Execute a pipeline with DML stage within an explicit transaction Pipeline pipeline = db.pipeline() .collection("users") .where(field("active").equal(false)) .addFields(constant("inactive").as("status")) .update(); db.runTransaction(transaction -\> { transaction.execute(pipeline); return null; }); \`\`\`

#### Using the `atomic` option

##### Node.js

\`\`\`js // Execute a pipeline const results = await db.pipeline() .collection("users") .where(field("active").equal(false)) .addFields(constant("inactive").as("status")) .update() .execute({ atomic: true }); \`\`\`

##### Java

\`\`\`java // Execute a pipeline passing atomic option to execute() Pipeline pipeline = db.pipeline() .collection("users") .where(field("active").equal(false)) .addFields(constant("inactive").as("status")) .update(); pipeline.execute(new PipelineExecuteOptions().withAtomic(true)); \`\`\`