Conversor usado por withConverter()
para transformar objetos de usuário do tipo AppModelType
em dados do Firestore do tipo DbModelType
.
O uso do conversor permite especificar argumentos de tipo genérico ao armazenar e recuperar objetos do Firestore.
Neste contexto, um "AppModel" é uma classe usada em um aplicativo para empacotar informações e funcionalidades relacionadas. Essa classe poderia, por exemplo, ter propriedades com tipos de dados complexos e aninhados, propriedades usadas para memorização, propriedades de tipos não suportados pelo Firestore (como symbol
e bigint
) e funções auxiliares que executam operações compostas. Essas classes não são adequadas e/ou possíveis de serem armazenadas em um banco de dados Firestore. Em vez disso, as instâncias de tais classes precisam ser convertidas em "objetos JavaScript simples e antigos" (POJOs) com propriedades exclusivamente primitivas, potencialmente aninhadas dentro de outros POJOs ou matrizes de POJOs. Nesse contexto, esse tipo é conhecido como "DbModel" e seria um objeto adequado para persistir no Firestore. Por conveniência, os aplicativos podem implementar FirestoreDataConverter
e registrar o conversor com objetos Firestore, como DocumentReference
ou Query
, para converter automaticamente AppModel
em DbModel
ao armazenar no Firestore e converter DbModel
em AppModel
ao recuperar do Firestore.
Assinatura:
export declare interface FirestoreDataConverter<AppModelType, DbModelType extends DocumentData = DocumentData>
Métodos
Método | Descrição |
---|---|
do Firestore (instantâneo) | Chamado pelo SDK do Firestore para converter dados do Firestore em um objeto do tipo AppModelType . Você pode acessar seus dados chamando: snapshot.data() . Geralmente, os dados retornados de snapshot.data() podem ser convertidos em DbModelType ; no entanto, isso não é garantido porque o Firestore não impõe um esquema ao banco de dados. Por exemplo, gravações de uma versão anterior do aplicativo ou gravações de outro cliente que não usou um conversor de tipo podem ter gravado dados com propriedades e/ou tipos de propriedade diferentes. A implementação precisará escolher se deseja recuperar normalmente de dados não conformes ou gerar um erro. |
paraFirestore(modelObject) | Chamado pelo SDK do Firestore para converter um objeto de modelo personalizado do tipo AppModelType em um objeto Javascript simples (adequado para gravar diretamente no banco de dados do Firestore) do tipo DbModelType . Usado com setDoc() , e . O tipo WithFieldValue<T> estende T para também permitir que FieldValues como deleteField() sejam usados como valores de propriedade. |
toFirestore(modelObject, opções) | Chamado pelo SDK do Firestore para converter um objeto de modelo personalizado do tipo AppModelType em um objeto Javascript simples (adequado para gravar diretamente no banco de dados do Firestore) do tipo DbModelType . Usado com setDoc() e com merge:true ou mergeFields . O tipo PartialWithFieldValue<T> estende Partial<T> para permitir que FieldValues como arrayUnion() sejam usados como valores de propriedade. Ele também oferece suporte Partial aninhado, permitindo que campos aninhados sejam omitidos. |
FirestoreDataConverter.fromFirestore()
Chamado pelo SDK do Firestore para converter dados do Firestore em um objeto do tipo AppModelType
. Você pode acessar seus dados chamando: snapshot.data()
.
Geralmente, os dados retornados de snapshot.data()
podem ser convertidos em DbModelType
; no entanto, isso não é garantido porque o Firestore não impõe um esquema ao banco de dados. Por exemplo, gravações de uma versão anterior do aplicativo ou gravações de outro cliente que não usou um conversor de tipo podem ter gravado dados com propriedades e/ou tipos de propriedade diferentes. A implementação precisará escolher se deseja recuperar normalmente de dados não conformes ou gerar um erro.
Assinatura:
fromFirestore(snapshot: QueryDocumentSnapshot<DocumentData, DocumentData>): AppModelType;
Parâmetros
Parâmetro | Tipo | Descrição |
---|---|---|
instantâneo | QueryDocumentSnapshot < DocumentData , DadosDoDocumento > | Um QueryDocumentSnapshot contendo seus dados e metadados. |
Retorna:
AppModelType
FirestoreDataConverter.toFirestore()
Chamado pelo SDK do Firestore para converter um objeto de modelo personalizado do tipo AppModelType
em um objeto Javascript simples (adequado para gravar diretamente no banco de dados do Firestore) do tipo DbModelType
. Usado com setDoc() , e .
O tipo WithFieldValue<T>
estende T
para também permitir que FieldValues como deleteField() sejam usados como valores de propriedade.
Assinatura:
toFirestore(modelObject: WithFieldValue<AppModelType>): WithFieldValue<DbModelType>;
Parâmetros
Parâmetro | Tipo | Descrição |
---|---|---|
modeloObject | ComFieldValue <AppModelType> |
Retorna:
ComFieldValue <DbModelType>
FirestoreDataConverter.toFirestore()
Chamado pelo SDK do Firestore para converter um objeto de modelo personalizado do tipo AppModelType
em um objeto Javascript simples (adequado para gravar diretamente no banco de dados do Firestore) do tipo DbModelType
. Usado com setDoc() , e com merge:true
ou mergeFields
.
O tipo PartialWithFieldValue<T>
estende Partial<T>
para permitir que FieldValues como arrayUnion() sejam usados como valores de propriedade. Ele também oferece suporte Partial
aninhado, permitindo que campos aninhados sejam omitidos.
Assinatura:
toFirestore(modelObject: PartialWithFieldValue<AppModelType>, options: SetOptions): PartialWithFieldValue<DbModelType>;
Parâmetros
Parâmetro | Tipo | Descrição |
---|---|---|
modeloObject | PartialWithFieldValue <AppModelType> | |
opções | Definir opções |
Retorna:
PartialWithFieldValue <DbModelType>
Exemplo
Exemplo simples
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);
}
Exemplo Avançado
// 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');
}
}