updateDoc method

Future<TurboResponse<DocumentReference<Object?>>> updateDoc({
  1. required TurboWriteable writeable,
  2. required String id,
  3. WriteBatch? writeBatch,
  4. TurboTimestampType timestampType = TurboTimestampType.updatedAt,
  5. String? collectionPathOverride,
  6. Transaction? transaction,
})

Updates an existing document in Firestore

Modifies document data while preserving fields not included in writeable Automatically manages timestamps based on timestampType

Parameters: writeable data to update, must implement TurboWriteable id unique identifier of the document writeBatch optional batch to include this operation in timestampType type of timestamp to add when updating collectionPathOverride override path for collection groups transaction optional transaction to include this operation in

Returns TurboResponse containing:

  • Success with document reference
  • Fail with validation or operation errors

Features:

  • Automatic validation
  • Timestamp management
  • Batch operation support
  • Transaction support
  • Error logging

Example:

final user = User(name: 'John Updated');
final response = await api.updateDoc(
  writeable: user,
  id: 'user-123',
);
response.when(
  success: (ref) => print('Updated user ${ref.id}'),
  fail: (error) => print('Error $error'),
);

See also: updateDocInBatch batch updates createDoc document creation

Implementation

Future<TurboResponse<DocumentReference>> updateDoc({
  required TurboWriteable writeable,
  required String id,
  WriteBatch? writeBatch,
  TurboTimestampType timestampType = TurboTimestampType.updatedAt,
  String? collectionPathOverride,
  Transaction? transaction,
}) async {
  assert(
    _isCollectionGroup == (collectionPathOverride != null),
    'Firestore does not support finding a document by id when communicating with a collection group, '
    'therefore, you must specify the collectionPathOverride containing all parent collection and document ids '
    'in order to make this method work.',
  );
  try {
    _log.debug(
      message: 'Checking if writeable is valid..',
      sensitiveData: null,
    );
    final TurboResponse<DocumentReference>? invalidResponse =
        writeable.validate();
    if (invalidResponse != null && invalidResponse.isFail) {
      _log.warning(
        message: 'TurboWriteable was invalid!',
        sensitiveData: null,
      );
      return invalidResponse;
    }
    _log.info(message: 'TurboWriteable is valid!', sensitiveData: null);
    _log.debug(
      message: 'Updating document..',
      sensitiveData: SensitiveData(
        path: collectionPathOverride ?? _collectionPath(),
        id: id,
        isBatch: writeBatch != null,
        isTransaction: transaction != null,
        updateTimeStampType: timestampType,
      ),
    );
    if (writeBatch != null) {
      _log.debug(
        message: 'WriteBatch was not null! Updating with batch..',
        sensitiveData: null,
      );
      final lastBatchResponse = await updateDocInBatch(
        writeable: writeable,
        id: id,
        writeBatch: writeBatch,
        timestampType: timestampType,
        collectionPathOverride: collectionPathOverride,
      );
      _log.debug(
        message: 'Checking if batchUpdate was successful..',
        sensitiveData: null,
      );
      return _handleBatchOperation(lastBatchResponse);
    } else {
      _log.debug(
        message: 'WriteBatch was null! Updating without batch..',
        sensitiveData: null,
      );
      final documentReference = getDocRefById(
          id: id, collectionPathOverride: collectionPathOverride);
      _log.debug(
        message: 'Creating JSON..',
        sensitiveData: null,
      );
      final writeableAsJson = timestampType.add(
        writeable.toJson(),
        createdAtFieldName: _createdAtFieldName,
        updatedAtFieldName: _updatedAtFieldName,
      );
      if (transaction == null) {
        _log.debug(
          message: 'Updating data with documentReference.update..',
          sensitiveData: SensitiveData(
            path: collectionPathOverride ?? _collectionPath(),
            id: documentReference.id,
            data: writeableAsJson,
          ),
        );
        await documentReference.update(writeableAsJson);
      } else {
        _log.debug(
          message: 'Updating data with transaction.update..',
          sensitiveData: SensitiveData(
            path: collectionPathOverride ?? _collectionPath(),
            id: documentReference.id,
            data: writeableAsJson,
          ),
        );
        transaction.update(
            getDocRefById(id: documentReference.id), writeableAsJson);
      }
      _log.info(
        message: 'Updating data done!',
        sensitiveData: null,
      );
      return TurboResponse.success(result: documentReference);
    }
  } catch (error, stackTrace) {
    if (transaction != null) {
      // Wrap and rethrow for transactions
      throw TurboFirestoreException.fromFirestoreException(
        error,
        stackTrace,
        path: collectionPathOverride ?? _collectionPath(),
        query: 'updateDoc(id: $id)',
      );
    }

    _log.error(
      message: 'Unable to update document',
      sensitiveData: SensitiveData(
        path: collectionPathOverride ?? _collectionPath(),
        id: id,
        isBatch: writeBatch != null,
        updateTimeStampType: timestampType,
      ),
      error: error,
      stackTrace: stackTrace,
    );

    // Convert to TurboFirestoreException and wrap in TurboResponse
    final exception = TurboFirestoreException.fromFirestoreException(
      error,
      stackTrace,
      path: collectionPathOverride ?? _collectionPath(),
      query: 'updateDoc(id: $id)',
    );

    return TurboResponse.fail(error: exception);
  }
}