FirestoreDataConverter interface

Konverter yang digunakan oleh withConverter() untuk mengubah objek pengguna bertipe AppModelType menjadi data Firestore bertipe DbModelType .

Menggunakan konverter memungkinkan Anda menentukan argumen tipe umum saat menyimpan dan mengambil objek dari Firestore.

Dalam konteks ini, "AppModel" adalah kelas yang digunakan dalam aplikasi untuk mengemas informasi dan fungsionalitas terkait. Kelas seperti itu, misalnya, dapat memiliki properti dengan tipe data yang kompleks dan bertingkat, properti yang digunakan untuk memoisasi, properti dengan tipe yang tidak didukung oleh Firestore (seperti symbol dan bigint ), dan fungsi pembantu yang melakukan operasi gabungan. Kelas seperti itu tidak cocok dan/atau tidak mungkin disimpan ke dalam database Firestore. Sebaliknya, instance dari kelas tersebut perlu dikonversi menjadi "objek JavaScript lama biasa" (POJO) dengan properti primitif eksklusif, yang berpotensi bersarang di dalam POJO atau array POJO lain. Dalam konteks ini, tipe ini disebut sebagai "DbModel" dan akan menjadi objek yang cocok untuk disimpan di Firestore. Untuk kenyamanan, aplikasi dapat mengimplementasikan FirestoreDataConverter dan mendaftarkan konverter dengan objek Firestore, seperti DocumentReference atau Query , untuk secara otomatis mengonversi AppModel ke DbModel saat menyimpan ke Firestore, dan mengonversi DbModel ke AppModel saat mengambil dari Firestore.

Tanda tangan:

export declare interface FirestoreDataConverter<AppModelType, DbModelType extends DocumentData = DocumentData> 

Metode

metode Keterangan
fromFirestore(snapshot, opsi) Dipanggil oleh Firestore SDK untuk mengonversi data Firestore menjadi objek bertipe AppModelType . Anda dapat mengakses data Anda dengan menelepon: snapshot.data(options) . Umumnya, data yang dikembalikan dari snapshot.data() dapat ditransfer ke DbModelType ; namun, hal ini tidak dijamin karena Firestore tidak menerapkan skema pada database. Misalnya, menulis dari versi aplikasi sebelumnya atau menulis dari klien lain yang tidak menggunakan pengonversi tipe dapat menulis data dengan properti dan/atau tipe properti berbeda. Implementasinya harus memilih apakah akan memulihkan data yang tidak sesuai dengan baik atau membuat kesalahan. Untuk mengganti metode ini, lihat .
keFirestore(modelObject) Dipanggil oleh Firestore SDK untuk mengonversi objek model khusus bertipe AppModelType menjadi objek JavaScript biasa (cocok untuk menulis langsung ke database Firestore) bertipe DbModelType . Untuk menggunakan set() dengan merge dan mergeFields , toFirestore() harus didefinisikan dengan PartialWithFieldValue<AppModelType> . Tipe WithFieldValue<T> memperluas T untuk juga mengizinkan FieldValues ​​seperti deleteField() digunakan sebagai nilai properti.
toFirestore(modelObject, opsi) Dipanggil oleh Firestore SDK untuk mengonversi objek model khusus bertipe AppModelType menjadi objek JavaScript biasa (cocok untuk menulis langsung ke database Firestore) bertipe DbModelType . Digunakan dengan setDoc() , dan dengan merge:true atau mergeFields . Tipe PartialWithFieldValue<T> memperluas Partial<T> untuk memungkinkan FieldValues ​​seperti arrayUnion() digunakan sebagai nilai properti. Ini juga mendukung Partial dengan mengizinkan bidang bersarang dihilangkan.

FirestoreDataConverter.fromFirestore()

Dipanggil oleh Firestore SDK untuk mengonversi data Firestore menjadi objek bertipe AppModelType . Anda dapat mengakses data Anda dengan menelepon: snapshot.data(options) .

Umumnya, data yang dikembalikan dari snapshot.data() dapat ditransfer ke DbModelType ; namun, hal ini tidak dijamin karena Firestore tidak menerapkan skema pada database. Misalnya, menulis dari versi aplikasi sebelumnya atau menulis dari klien lain yang tidak menggunakan pengonversi tipe dapat menulis data dengan properti dan/atau tipe properti berbeda. Implementasinya harus memilih apakah akan memulihkan data yang tidak sesuai dengan baik atau membuat kesalahan.

Untuk mengganti metode ini, lihat .

Tanda tangan:

fromFirestore(snapshot: QueryDocumentSnapshot<DocumentData, DocumentData>, options?: SnapshotOptions): AppModelType;

Parameter

Parameter Jenis Keterangan
foto Cuplikan Dokumen Kueri < Data Dokumen , Data Dokumen > QueryDocumentSnapshot yang berisi data dan metadata Anda.
pilihan Opsi Snapshot SnapshotOptions dari panggilan awal ke data() .

Pengembalian:

Tipe Model Aplikasi

FirestoreDataConverter.toFirestore()

Dipanggil oleh Firestore SDK untuk mengonversi objek model khusus bertipe AppModelType menjadi objek JavaScript biasa (cocok untuk menulis langsung ke database Firestore) bertipe DbModelType . Untuk menggunakan set() dengan merge dan mergeFields , toFirestore() harus didefinisikan dengan PartialWithFieldValue<AppModelType> .

Tipe WithFieldValue<T> memperluas T untuk juga mengizinkan FieldValues ​​seperti deleteField() digunakan sebagai nilai properti.

Tanda tangan:

toFirestore(modelObject: WithFieldValue<AppModelType>): WithFieldValue<DbModelType>;

Parameter

Parameter Jenis Keterangan
modelObjek DenganFieldValue <JenisModel Aplikasi>

Pengembalian:

DenganFieldValue <DbModelType>

FirestoreDataConverter.toFirestore()

Dipanggil oleh Firestore SDK untuk mengonversi objek model khusus bertipe AppModelType menjadi objek JavaScript biasa (cocok untuk menulis langsung ke database Firestore) bertipe DbModelType . Digunakan dengan setDoc() , dan dengan merge:true atau mergeFields .

Tipe PartialWithFieldValue<T> memperluas Partial<T> untuk memungkinkan FieldValues ​​seperti arrayUnion() digunakan sebagai nilai properti. Ini juga mendukung Partial dengan mengizinkan bidang bersarang dihilangkan.

Tanda tangan:

toFirestore(modelObject: PartialWithFieldValue<AppModelType>, options: SetOptions): PartialWithFieldValue<DbModelType>;

Parameter

Parameter Jenis Keterangan
modelObjek PartialWithFieldValue <JenisModel Aplikasi>
pilihan Set Opsi

Pengembalian:

PartialWithFieldValue <DbModelType>

Contoh

Contoh Sederhana

const numberConverter = {
    toFirestore(value: WithFieldValue<number>) {
        return { value };
    },
    fromFirestore(snapshot: QueryDocumentSnapshot, options: SnapshotOptions) {
        return snapshot.data(options).value as number;
    }
};

async function simpleDemo(db: Firestore): Promise<void> {
    const documentRef = doc(db, 'values/value123').withConverter(numberConverter);

    // converters are used with `setDoc`, `addDoc`, and `getDoc`
    await setDoc(documentRef, 42);
    const snapshot1 = await getDoc(documentRef);
    assertEqual(snapshot1.data(), 42);

    // converters are not used when writing data with `updateDoc`
    await updateDoc(documentRef, { value: 999 });
    const snapshot2 = await getDoc(documentRef);
    assertEqual(snapshot2.data(), 999);
}

Contoh Lanjutan

// The Post class is a model that is used by our application.
// This class may have properties and methods that are specific
// to our application execution, which do not need to be persisted
// to Firestore.
class Post {
    constructor(
        readonly title: string,
        readonly author: string,
        readonly lastUpdatedMillis: number
    ) {}
    toString(): string {
        return `${this.title} by ${this.author}`;
    }
}

// The PostDbModel represents how we want our posts to be stored
// in Firestore. This DbModel has different properties (`ttl`,
// `aut`, and `lut`) from the Post class we use in our application.
interface PostDbModel {
    ttl: string;
    aut: { firstName: string; lastName: string };
    lut: Timestamp;
}

// The `PostConverter` implements `FirestoreDataConverter` and specifies
// how the Firestore SDK can convert `Post` objects to `PostDbModel`
// objects and vice versa.
class PostConverter implements FirestoreDataConverter<Post, PostDbModel> {
    toFirestore(post: WithFieldValue<Post>): WithFieldValue<PostDbModel> {
        return {
            ttl: post.title,
            aut: this._autFromAuthor(post.author),
            lut: this._lutFromLastUpdatedMillis(post.lastUpdatedMillis)
        };
    }

    fromFirestore(snapshot: QueryDocumentSnapshot, options: SnapshotOptions): Post {
        const data = snapshot.data(options) as PostDbModel;
        const author = `${data.aut.firstName} ${data.aut.lastName}`;
        return new Post(data.ttl, author, data.lut.toMillis());
    }

    _autFromAuthor(
        author: string | FieldValue
    ): { firstName: string; lastName: string } | FieldValue {
        if (typeof author !== 'string') {
            // `author` is a FieldValue, so just return it.
            return author;
        }
        const [firstName, lastName] = author.split(' ');
        return {firstName, lastName};
    }

    _lutFromLastUpdatedMillis(
        lastUpdatedMillis: number | FieldValue
    ): Timestamp | FieldValue {
        if (typeof lastUpdatedMillis !== 'number') {
            // `lastUpdatedMillis` must be a FieldValue, so just return it.
            return lastUpdatedMillis;
        }
        return Timestamp.fromMillis(lastUpdatedMillis);
    }
}

async function advancedDemo(db: Firestore): Promise<void> {
    // Create a `DocumentReference` with a `FirestoreDataConverter`.
    const documentRef = doc(db, 'posts/post123').withConverter(new PostConverter());

    // The `data` argument specified to `setDoc()` is type checked by the
    // TypeScript compiler to be compatible with `Post`. Since the `data`
    // argument is typed as `WithFieldValue<Post>` rather than just `Post`,
    // this allows properties of the `data` argument to also be special
    // Firestore values that perform server-side mutations, such as
    // `arrayRemove()`, `deleteField()`, and `serverTimestamp()`.
    await setDoc(documentRef, {
        title: 'My Life',
        author: 'Foo Bar',
        lastUpdatedMillis: serverTimestamp()
    });

    // The TypeScript compiler will fail to compile if the `data` argument to
    // `setDoc()` is _not_ compatible with `WithFieldValue<Post>`. This
    // type checking prevents the caller from specifying objects with incorrect
    // properties or property values.
    // @ts-expect-error "Argument of type { ttl: string; } is not assignable
    // to parameter of type WithFieldValue<Post>"
    await setDoc(documentRef, { ttl: 'The Title' });

    // When retrieving a document with `getDoc()` the `DocumentSnapshot`
    // object's `data()` method returns a `Post`, rather than a generic object,
    // which would have been returned if the `DocumentReference` did _not_ have a
    // `FirestoreDataConverter` attached to it.
    const snapshot1: DocumentSnapshot<Post> = await getDoc(documentRef);
    const post1: Post = snapshot1.data()!;
    if (post1) {
        assertEqual(post1.title, 'My Life');
        assertEqual(post1.author, 'Foo Bar');
    }

    // The `data` argument specified to `updateDoc()` is type checked by the
    // TypeScript compiler to be compatible with `PostDbModel`. Note that
    // unlike `setDoc()`, whose `data` argument must be compatible with `Post`,
    // the `data` argument to `updateDoc()` must be compatible with
    // `PostDbModel`. Similar to `setDoc()`, since the `data` argument is typed
    // as `WithFieldValue<PostDbModel>` rather than just `PostDbModel`, this
    // allows properties of the `data` argument to also be those special
    // Firestore values, like `arrayRemove()`, `deleteField()`, and
    // `serverTimestamp()`.
    await updateDoc(documentRef, {
        'aut.firstName': 'NewFirstName',
        lut: serverTimestamp()
    });

    // The TypeScript compiler will fail to compile if the `data` argument to
    // `updateDoc()` is _not_ compatible with `WithFieldValue<PostDbModel>`.
    // This type checking prevents the caller from specifying objects with
    // incorrect properties or property values.
    // @ts-expect-error "Argument of type { title: string; } is not assignable
    // to parameter of type WithFieldValue<PostDbModel>"
    await updateDoc(documentRef, { title: 'New Title' });
    const snapshot2: DocumentSnapshot<Post> = await getDoc(documentRef);
    const post2: Post = snapshot2.data()!;
    if (post2) {
        assertEqual(post2.title, 'My Life');
        assertEqual(post2.author, 'NewFirstName Bar');
    }
}