FirestoreDataConverter interface

Convertitore utilizzato da withConverter() per trasformare oggetti utente di tipo AppModelType in dati Firestore di tipo DbModelType .

L'utilizzo del convertitore consente di specificare argomenti di tipo generico durante l'archiviazione e il recupero di oggetti da Firestore.

In questo contesto, un "AppModel" è una classe utilizzata in un'applicazione per assemblare insieme informazioni e funzionalità correlate. Una classe di questo tipo potrebbe, ad esempio, avere proprietà con tipi di dati complessi e nidificati, proprietà utilizzate per la memorizzazione, proprietà di tipi non supportati da Firestore (come symbol e bigint ) e funzioni di supporto che eseguono operazioni composte. Tali classi non sono adatte e/o non è possibile archiviarle in un database Firestore. Invece, le istanze di tali classi devono essere convertite in "piani vecchi oggetti JavaScript" (POJO) con proprietà esclusivamente primitive, potenzialmente annidate all'interno di altri POJO o array di POJO. In questo contesto, questo tipo viene chiamato "DbModel" e sarebbe un oggetto adatto a persistere in Firestore. Per comodità, le applicazioni possono implementare FirestoreDataConverter e registrare il convertitore con oggetti Firestore, come DocumentReference o Query , per convertire automaticamente AppModel in DbModel durante l'archiviazione in Firestore e convertire DbModel in AppModel durante il recupero da Firestore.

Firma:

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

Metodi

Metodo Descrizione
daFirestore(istantanea) Chiamato dall'SDK di Firestore per convertire i dati Firestore in un oggetto di tipo AppModelType . Puoi accedere ai tuoi dati chiamando: snapshot.data() . In genere, i dati restituiti da snapshot.data() possono essere sottoposti a cast su DbModelType ; tuttavia, ciò non è garantito perché Firestore non applica uno schema al database. Ad esempio, le scritture da una versione precedente dell'applicazione o le scritture da un altro client che non utilizzava un convertitore di tipi potrebbero aver scritto dati con proprietà e/o tipi di proprietà diversi. L'implementazione dovrà scegliere se eseguire il ripristino con garbo dai dati non conformi o generare un errore.
toFirestore(modelloOggetto) Chiamato dall'SDK di Firestore per convertire un oggetto del modello personalizzato di tipo AppModelType in un semplice oggetto Javascript (adatto per scrivere direttamente nel database Firestore) di tipo DbModelType . Utilizzato con setDoc() , E . Il tipo WithFieldValue<T> estende T per consentire anche l'utilizzo di FieldValue come deleteField() come valori di proprietà.
toFirestore(modelObject, opzioni) Chiamato dall'SDK di Firestore per convertire un oggetto del modello personalizzato di tipo AppModelType in un semplice oggetto Javascript (adatto per scrivere direttamente nel database Firestore) di tipo DbModelType . Utilizzato con setDoc() e con merge:true o mergeFields . Il tipo PartialWithFieldValue<T> estende Partial<T> per consentire l'utilizzo di FieldValue come arrayUnion() come valori di proprietà. Supporta anche Partial nidificato consentendo l'omissione dei campi nidificati.

FirestoreDataConverter.fromFirestore()

Chiamato dall'SDK di Firestore per convertire i dati Firestore in un oggetto di tipo AppModelType . Puoi accedere ai tuoi dati chiamando: snapshot.data() .

In genere, i dati restituiti da snapshot.data() possono essere sottoposti a cast su DbModelType ; tuttavia, ciò non è garantito perché Firestore non applica uno schema al database. Ad esempio, le scritture da una versione precedente dell'applicazione o le scritture da un altro client che non utilizzava un convertitore di tipi potrebbero aver scritto dati con proprietà e/o tipi di proprietà diversi. L'implementazione dovrà scegliere se eseguire il ripristino con garbo dai dati non conformi o generare un errore.

Firma:

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

Parametri

Parametro Tipo Descrizione
istantanea QueryDocumentSnapshot < Dati documento , Dati documento > Un QueryDocumentSnapshot contenente i dati e i metadati.

Ritorna:

AppModelType

FirestoreDataConverter.toFirestore()

Chiamato dall'SDK di Firestore per convertire un oggetto modello personalizzato di tipo AppModelType in un semplice oggetto Javascript (adatto per scrivere direttamente nel database Firestore) di tipo DbModelType . Utilizzato con setDoc() , E .

Il tipo WithFieldValue<T> estende T per consentire anche l'utilizzo di FieldValue come deleteField() come valori di proprietà.

Firma:

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

Parametri

Parametro Tipo Descrizione
modelloOggetto ConFieldValue <AppModelType>

Ritorna:

ConFieldValue <TipomodelloDb>

FirestoreDataConverter.toFirestore()

Chiamato dall'SDK di Firestore per convertire un oggetto modello personalizzato di tipo AppModelType in un semplice oggetto Javascript (adatto per scrivere direttamente nel database Firestore) di tipo DbModelType . Utilizzato con setDoc() e con merge:true o mergeFields .

Il tipo PartialWithFieldValue<T> estende Partial<T> per consentire l'utilizzo di FieldValue come arrayUnion() come valori di proprietà. Supporta anche Partial nidificato consentendo l'omissione dei campi nidificati.

Firma:

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

Parametri

Parametro Tipo Descrizione
modelloOggetto ParzialeConFieldValue <AppModelType>
opzioni Imposta opzioni

Ritorna:

ParzialeConFieldValue <TipomodelloDb>

Esempio

Esempio semplice

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);
}

Esempio avanzato

// 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');
    }
}