FirestoreDataConverter interface

Konverter, der von withConverter() verwendet wird, um Benutzerobjekte vom Typ AppModelType in Firestore-Daten vom Typ DbModelType umzuwandeln .

Mit dem Konverter können Sie beim Speichern und Abrufen von Objekten aus Firestore generische Typargumente angeben.

In diesem Zusammenhang ist ein „AppModel“ eine Klasse, die in einer Anwendung verwendet wird, um verwandte Informationen und Funktionen zusammenzufassen. Eine solche Klasse könnte beispielsweise Eigenschaften mit komplexen, verschachtelten Datentypen, Eigenschaften für die Memoisierung oder Eigenschaften von Typen haben, die von Firestore nicht unterstützt werden (z. B. symbol und bigint . ) und Hilfsfunktionen, die zusammengesetzte Operationen ausführen. Solche Klassen eignen sich nicht und/oder können nicht in einer Firestore-Datenbank gespeichert werden. Stattdessen müssen Instanzen solcher Klassen in „einfache alte JavaScript-Objekte“ (POJOs) mit ausschließlich primitiven Eigenschaften konvertiert werden, die möglicherweise in anderen POJOs oder Arrays von POJOs verschachtelt sind. In diesem Zusammenhang wird dieser Typ als „DbModel“ bezeichnet und wäre ein Objekt, das sich für die Beibehaltung im Firestore eignet. Der Einfachheit halber können Anwendungen FirestoreDataConverter implementieren und den Konverter bei Firestore-Objekten wie DocumentReference oder Query registrieren , um AppModel beim Speichern im Firestore automatisch in DbModel zu konvertieren und DbModel beim Abrufen aus Firestore automatisch in AppModel zu konvertieren.

Unterschrift:

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

Methoden

Methode Beschreibung
fromFirestore(Schnappschuss) Wird vom Firestore SDK aufgerufen, um Firestore-Daten in ein Objekt vom Typ AppModelType zu konvertieren. Sie können auf Ihre Daten zugreifen, indem Sie Folgendes aufrufen: snapshot.data() . Im Allgemeinen können die von snapshot.data() zurückgegebenen Daten in DbModelType umgewandelt werden; Dies kann jedoch nicht garantiert werden, da Firestore kein Schema für die Datenbank erzwingt. Beispielsweise könnten Schreibvorgänge aus einer früheren Version der Anwendung oder Schreibvorgänge von einem anderen Client, der keinen Typkonverter verwendet, Daten mit unterschiedlichen Eigenschaften und/oder Eigenschaftstypen geschrieben haben. Die Implementierung muss entscheiden, ob eine ordnungsgemäße Wiederherstellung bei nicht konformen Daten erfolgen soll oder ob ein Fehler ausgegeben werden soll.
toFirestore(modelObject) Wird vom Firestore SDK aufgerufen, um ein benutzerdefiniertes Modellobjekt vom Typ AppModelType in ein einfaches Javascript-Objekt (geeignet zum direkten Schreiben in die Firestore-Datenbank) vom Typ DbModelType zu konvertieren. Wird mit setDoc() verwendet , Und . Der Typ WithFieldValue<T> erweitert T , um auch die Verwendung von FieldValues ​​wie deleteField() als Eigenschaftswerte zu ermöglichen.
toFirestore(modelObject, Optionen) Wird vom Firestore SDK aufgerufen, um ein benutzerdefiniertes Modellobjekt vom Typ AppModelType in ein einfaches Javascript-Objekt (geeignet zum direkten Schreiben in die Firestore-Datenbank) vom Typ DbModelType zu konvertieren. Wird mit setDoc() verwendet und mit merge:true oder mergeFields . Der Typ PartialWithFieldValue<T> erweitert Partial<T> , um die Verwendung von FieldValues ​​wie arrayUnion() als Eigenschaftswerte zu ermöglichen. Es unterstützt auch verschachtelte Partial , indem es das Weglassen verschachtelter Felder ermöglicht.

FirestoreDataConverter.fromFirestore()

Wird vom Firestore SDK aufgerufen, um Firestore-Daten in ein Objekt vom Typ AppModelType zu konvertieren . Sie können auf Ihre Daten zugreifen, indem Sie Folgendes aufrufen: snapshot.data() .

Im Allgemeinen können die von snapshot.data() zurückgegebenen Daten in DbModelType umgewandelt werden ; Dies kann jedoch nicht garantiert werden, da Firestore kein Schema für die Datenbank erzwingt. Beispielsweise könnten Schreibvorgänge aus einer früheren Version der Anwendung oder Schreibvorgänge von einem anderen Client, der keinen Typkonverter verwendet, Daten mit unterschiedlichen Eigenschaften und/oder Eigenschaftstypen geschrieben haben. Die Implementierung muss entscheiden, ob eine ordnungsgemäße Wiederherstellung bei nicht konformen Daten erfolgen soll oder ob ein Fehler ausgegeben werden soll.

Unterschrift:

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

Parameter

Parameter Typ Beschreibung
Schnappschuss QueryDocumentSnapshot < Dokumentdaten , Dokumentdaten > Ein QueryDocumentSnapshot , der Ihre Daten und Metadaten enthält.

Kehrt zurück:

AppModelType

FirestoreDataConverter.toFirestore()

Wird vom Firestore SDK aufgerufen, um ein benutzerdefiniertes Modellobjekt vom Typ AppModelType in ein einfaches Javascript-Objekt (geeignet zum direkten Schreiben in die Firestore-Datenbank) vom Typ DbModelType zu konvertieren . Wird mit setDoc() verwendet , Und .

Der Typ WithFieldValue<T> erweitert T , um auch die Verwendung von FieldValues ​​wie deleteField() als Eigenschaftswerte zu ermöglichen.

Unterschrift:

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

Parameter

Parameter Typ Beschreibung
modelObject WithFieldValue <AppModelType>

Kehrt zurück:

WithFieldValue <DbModelType>

FirestoreDataConverter.toFirestore()

Wird vom Firestore SDK aufgerufen, um ein benutzerdefiniertes Modellobjekt vom Typ AppModelType in ein einfaches Javascript-Objekt (geeignet zum direkten Schreiben in die Firestore-Datenbank) vom Typ DbModelType zu konvertieren . Wird mit setDoc() verwendet und mit merge:true oder mergeFields .

Der Typ PartialWithFieldValue<T> erweitert Partial<T> , um die Verwendung von FieldValues ​​wie arrayUnion() als Eigenschaftswerte zu ermöglichen. Es unterstützt auch verschachtelte Partial , indem es das Weglassen verschachtelter Felder ermöglicht.

Unterschrift:

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

Parameter

Parameter Typ Beschreibung
modelObject PartialWithFieldValue <AppModelType>
Optionen SetOptions

Kehrt zurück:

PartialWithFieldValue <DbModelType>

Beispiel

Einfaches Beispiel

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

Erweitertes Beispiel

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