Skip to content
On this page

Document ID

A critical feature of this ODM is its seamless and automatic handling of Firestore document IDs.

The Role of the Document ID

Every document in Firestore has a unique ID. In your data model, you need a corresponding field to hold this ID. This is essential for the ODM to know which document to create, read, update, or delete.

By default, the ODM assumes this field is named id.

The @DocumentIdField Annotation

You can designate any String field in your model as the document ID container by using the @DocumentIdField() annotation.

dart
import 'package:firestore_odm_annotation/firestore_odm_annotation.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'user.freezed.dart';
part 'user.g.dart';

@freezed
class User with _$User {
  const factory User({
    // This field will now be used as the document ID
    @DocumentIdField() required String uid,
    required String name,
    required String email,
  }) = _User;

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
}

Automatic Synchronization

The most important concept to understand is that the value of the field annotated with @DocumentIdField is never actually stored within the Firestore document's data.

The ODM handles the synchronization for you automatically:

  • When writing data (e.g., insert, upsert): The ODM takes the value from your annotated field (e.g., uid: 'jane-doe') and uses it as the actual Firestore document ID. The uid field itself is not saved in the document's fields.
  • When reading data (e.g., get, stream): The ODM fetches the document, reads its actual Firestore ID, and automatically populates the annotated field in your model object.

This ensures that your model always has access to the document ID, but you never store redundant data in Firestore, keeping your database clean and efficient.

Auto-Generated Document IDs

When you want Firestore to automatically generate a unique document ID, use the special constant:

dart
import 'package:firestore_odm/firestore_odm.dart';

await db.users.insert(User(
  id: FirestoreODM.autoGeneratedId, // Server generates unique ID
  name: 'John Doe',
  email: 'john@example.com',
));

This will cause Firestore to generate a unique document ID automatically. The generated ID will be available in the returned document when you read it back:

dart
// Insert with auto-generated ID
await db.users.insert(User(
  id: FirestoreODM.autoGeneratedId,
  name: 'Auto User',
  email: 'auto@example.com',
));

// Query to find the user (since we don't know the generated ID)
final users = await db.users
  .where(($) => $.email(isEqualTo: 'auto@example.com'))
  .get();

if (users.isNotEmpty) {
  final user = users.first;
  print('Generated ID: ${user.id}'); // Shows the auto-generated ID
}

When to Use Auto-Generated IDs

Auto-generated IDs are useful when:

  • You don't have a natural unique identifier for your documents
  • You want to ensure globally unique IDs without collision risk
  • You're creating documents in bulk and don't want to manage ID generation yourself
  • You're implementing a system where the ID doesn't need to be human-readable

When to Use Custom IDs

Custom IDs are better when:

  • You have a natural unique identifier (like email, username, etc.)
  • You need predictable, human-readable IDs
  • You want to reference documents by a known identifier
  • You're migrating from another system with existing IDs