Trình chuyển đổi mà withConverter()
sử dụng để chuyển đổi các đối tượng người dùng thuộc loại AppModelType
thành dữ liệu Firestore thuộc loại DbModelType
.
Việc sử dụng trình chuyển đổi cho phép bạn chỉ định các đối số kiểu chung khi lưu trữ và truy xuất đối tượng từ Firestore.
Trong trường hợp này, "AppModel" là một lớp được dùng trong ứng dụng để đóng gói thông tin và chức năng liên quan lại với nhau. Ví dụ: một lớp như vậy có thể có các thuộc tính với kiểu dữ liệu phức tạp và lồng ghép, các thuộc tính dùng để ghi nhớ, thuộc tính của các kiểu không được Firestore hỗ trợ (chẳng hạn như symbol
và bigint
) và các hàm trợ giúp thực hiện các thao tác phức hợp. Các lớp như vậy không phù hợp và/hoặc không thể lưu trữ vào cơ sở dữ liệu Firestore. Thay vào đó, các thực thể của lớp đó cần được chuyển đổi thành "đối tượng JavaScript cũ" (POJO) có các thuộc tính gốc hoàn toàn, có thể được lồng trong các POJO hoặc mảng POJO khác. Trong trường hợp này, loại này được gọi là "DbModel" và sẽ là đối tượng phù hợp để duy trì trong Firestore. Để thuận tiện, các ứng dụng có thể triển khai FirestoreDataConverter
và đăng ký trình chuyển đổi với các đối tượng Firestore, chẳng hạn như DocumentReference
hoặc Query
, để tự động chuyển đổi AppModel
thành DbModel
khi lưu trữ vào Firestore và chuyển đổi DbModel
thành AppModel
khi truy xuất từ Firestore.
Chữ ký:
export declare interface FirestoreDataConverter<AppModelType, DbModelType extends DocumentData = DocumentData>
Phương thức
Phương thức | Mô tả |
---|---|
fromFirestore(ảnh chụp nhanh, tuỳ chọn) | Được Firestore SDK gọi để chuyển đổi dữ liệu Firestore thành một đối tượng thuộc loại AppModelType . Bạn có thể truy cập vào dữ liệu của mình bằng cách gọi: snapshot.data(options) .Thông thường, dữ liệu mà snapshot.data() trả về có thể được truyền tới DbModelType ; tuy nhiên, điều này không được đảm bảo vì Firestore không thực thi giản đồ trên cơ sở dữ liệu. Ví dụ: hoạt động ghi từ phiên bản trước của ứng dụng hoặc ghi từ một ứng dụng khác không sử dụng trình chuyển đổi kiểu có thể có dữ liệu đã ghi với các thuộc tính và/hoặc kiểu thuộc tính khác nhau. Quá trình triển khai sẽ cần chọn xem có khôi phục dễ dàng từ dữ liệu không phù hợp hay tạo ra lỗi.Để ghi đè phương thức này, hãy xem phần . |
toFirestore(modelObject) | Được Firestore SDK gọi để chuyển đổi một đối tượng mô hình tuỳ chỉnh thuộc loại AppModelType thành một đối tượng JavaScript thuần tuý (phù hợp để ghi trực tiếp vào cơ sở dữ liệu Firestore) thuộc loại DbModelType . Để sử dụng set() với merge và mergeFields , toFirestore() phải được xác định bằng PartialWithFieldValue<AppModelType> .Loại WithFieldValue<T> mở rộng T để cũng cho phép sử dụng các trường giá trị như deleteField() làm giá trị thuộc tính. |
toFirestore(modelObject, tuỳ chọn) | Được Firestore SDK gọi để chuyển đổi một đối tượng mô hình tuỳ chỉnh thuộc loại AppModelType thành một đối tượng JavaScript thuần tuý (phù hợp để ghi trực tiếp vào cơ sở dữ liệu Firestore) thuộc loại DbModelType . Được dùng với setDoc() và merge:true hoặc mergeFields .Loại PartialWithFieldValue<T> mở rộng Partial<T> để cho phép các trường giá trị (như arrayUnion()) dùng làm giá trị thuộc tính. Tính năng này cũng hỗ trợ Partial lồng nhau bằng cách cho phép bỏ qua các trường lồng nhau. |
FirestoreDataConverter.fromFirestore()
Do Firestore SDK gọi để chuyển đổi dữ liệu Firestore thành một đối tượng thuộc loại AppModelType
. Bạn có thể truy cập vào dữ liệu của mình bằng cách gọi: snapshot.data(options)
.
Nhìn chung, dữ liệu do snapshot.data()
trả về có thể được truyền tới DbModelType
; tuy nhiên, điều này không được đảm bảo vì Firestore không thực thi giản đồ trên cơ sở dữ liệu. Ví dụ: hoạt động ghi từ phiên bản trước của ứng dụng hoặc ghi từ một ứng dụng khác không sử dụng trình chuyển đổi kiểu có thể có dữ liệu đã ghi với các thuộc tính và/hoặc kiểu thuộc tính khác nhau. Quá trình triển khai sẽ cần chọn xem có khôi phục dễ dàng từ dữ liệu không phù hợp hay tạo ra lỗi.
Để ghi đè phương thức này, hãy xem
Chữ ký:
fromFirestore(snapshot: QueryDocumentSnapshot<DocumentData, DocumentData>, options?: SnapshotOptions): AppModelType;
Thông số
Thông số | Loại | Mô tả |
---|---|---|
ảnh chụp nhanh | QueryDocumentSnapshot<DocumentData, DocumentData> | QueryDocumentSnapshot chứa dữ liệu và siêu dữ liệu của bạn. |
tuỳ chọn | Tuỳ chọn ảnh chụp nhanh | SnapshotOptions từ lệnh gọi ban đầu đến data() . |
Trường hợp trả lại hàng:
Loại mô hình ứng dụng
FirestoreDataConverter.toFirestore()
Được Firestore SDK gọi để chuyển đổi một đối tượng mô hình tuỳ chỉnh thuộc loại AppModelType
thành một đối tượng JavaScript thuần tuý (phù hợp để ghi trực tiếp vào cơ sở dữ liệu Firestore) thuộc loại DbModelType
. Để sử dụng set()
với merge
và mergeFields
, bạn phải xác định toFirestore()
bằng PartialWithFieldValue<AppModelType>
.
Loại WithFieldValue<T>
mở rộng T
để cũng cho phép sử dụng các giá trị trường (chẳng hạn như deleteField()) làm giá trị thuộc tính.
Chữ ký:
toFirestore(modelObject: WithFieldValue<AppModelType>): WithFieldValue<DbModelType>;
Thông số
Thông số | Loại | Mô tả |
---|---|---|
đối tượng mô hình | WithFieldValue<AppModelType> |
Trường hợp trả lại hàng:
WithFieldValue<DbModelType>
FirestoreDataConverter.toFirestore()
Được Firestore SDK gọi để chuyển đổi một đối tượng mô hình tuỳ chỉnh thuộc loại AppModelType
thành một đối tượng JavaScript thuần tuý (phù hợp để ghi trực tiếp vào cơ sở dữ liệu Firestore) thuộc loại DbModelType
. Được dùng với setDoc() và với merge:true
hoặc mergeFields
.
Loại PartialWithFieldValue<T>
mở rộng Partial<T>
để cho phép sử dụng các giá trị trường (như arrayUnion()) làm giá trị thuộc tính. Tính năng này cũng hỗ trợ Partial
lồng nhau bằng cách cho phép bỏ qua các trường lồng nhau.
Chữ ký:
toFirestore(modelObject: PartialWithFieldValue<AppModelType>, options: SetOptions): PartialWithFieldValue<DbModelType>;
Thông số
Thông số | Loại | Mô tả |
---|---|---|
đối tượng mô hình | Một phầnWithFieldValue<AppModelType> | |
tuỳ chọn | SetOptions |
Trường hợp trả lại hàng:
Một phầnWithFieldValue<DbModelType>
Ví dụ
Ví dụ đơn giản
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);
}
Ví dụ nâng cao
// 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');
}
}