FirestoreDataConverter interface

Trình chuyển đổi được 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ố loại chung khi lưu trữ và truy xuất các đối tượng từ Firestore.

Trong ngữ cảnh này, "AppModel" là một lớp được sử dụng trong một ứng dụng để đóng gói các 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 các kiểu dữ liệu lồng nhau, phức tạp, các thuộc tính được sử dụng để ghi nhớ, các thuộc tính của các loại không được Firestore hỗ trợ (chẳng hạn như symbolbigint ) và các hàm trợ giúp thực hiện các phép toán 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 phiên bản của các lớp như vậy cần phải được chuyển đổi thành "các đối tượng JavaScript cũ thuần túy" (POJO) với các thuộc tính nguyên thủy độc quyền, có khả năng được lồng bên trong các POJO hoặc mảng POJO khác. Trong ngữ cảnh 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 pháp

Phương pháp Sự miêu tả
fromFirestore(ảnh chụp nhanh, tùy chọn) Được SDK Firestore gọi để chuyển đổi dữ liệu Firestore thành đối tượng thuộc loại AppModelType . Bạn có thể truy cập dữ liệu của mình bằng cách gọi: snapshot.data(options) . Nói chung, dữ liệu được trả về từ snapshot.data() có thể được chuyển sang DbModelType ; tuy nhiên, điều này không được đảm bảo vì Firestore không thực thi lược đồ trên cơ sở dữ liệu. Ví dụ: ghi từ phiên bản trước của ứng dụng hoặc ghi từ máy khách khác không sử dụng trình chuyển đổi loại có thể có dữ liệu được ghi với các thuộc tính và/hoặc loại thuộc tính khác nhau. Việc triển khai sẽ cần phải chọn khôi phục một cách linh hoạt từ dữ liệu không tuân thủ hay đưa ra lỗi. Để ghi đè phương thức này, hãy xem .
toFirestore(modelObject) Được SDK Firestore gọi để chuyển đổi đối tượng mô hình tùy chỉnh thuộc loại AppModelType thành đối tượng JavaScript đơn giản (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 mergemergeFields , 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 FieldValues ​​như deleteField() làm giá trị thuộc tính.
toFirestore(modelObject, tùy chọn) Được SDK Firestore gọi để chuyển đổi đối tượng mô hình tùy chỉnh thuộc loại AppModelType thành đối tượng JavaScript đơn giản (phù hợp để ghi trực tiếp vào cơ sở dữ liệu Firestore) thuộc loại DbModelType . Được sử 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 các FieldValues ​​như arrayUnion() được sử dụng làm giá trị thuộc tính. Nó 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()

Được SDK Firestore gọi để chuyển đổi dữ liệu Firestore thành đối tượng thuộc loại AppModelType . Bạn có thể truy cập dữ liệu của mình bằng cách gọi: snapshot.data(options) .

Nói chung, dữ liệu được trả về từ snapshot.data() có thể được chuyển sang DbModelType ; tuy nhiên, điều này không được đảm bảo vì Firestore không thực thi lược đồ trên cơ sở dữ liệu. Ví dụ: ghi từ phiên bản trước của ứng dụng hoặc ghi từ máy khách khác không sử dụng trình chuyển đổi loại có thể có dữ liệu được ghi với các thuộc tính và/hoặc loại thuộc tính khác nhau. Việc triển khai sẽ cần phải chọn khôi phục một cách linh hoạt từ dữ liệu không tuân thủ hay đưa 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ố

Tham số Kiểu Sự miêu tả
ảnh chụp nhanh Ảnh chụp nhanh tài liệu truy vấn < Dữ liệu tài liệu , Dữ liệu tài liệu > QueryDocumentSnapshot chứa dữ liệu và siêu dữ liệu của bạn.
tùy chọn Tùy chọn ảnh chụp nhanh SnapshotOptions từ lệnh gọi đầu tiên tới data() .

Trả về:

AppModelType

FirestoreDataConverter.toFirestore()

Được SDK Firestore gọi để chuyển đổi đối tượng mô hình tùy chỉnh thuộc loại AppModelType thành đối tượng JavaScript đơn giản (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 mergemergeFields , 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 FieldValues ​​như deleteField() làm giá trị thuộc tính.

Chữ ký:

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

Thông số

Tham số Kiểu Sự miêu tả
đối tượng mô hình Với giá trị trường <AppModelType>

Trả về:

Với giá trị trường <DbModelType>

FirestoreDataConverter.toFirestore()

Được SDK Firestore gọi để chuyển đổi đối tượng mô hình tùy chỉnh thuộc loại AppModelType thành đối tượng JavaScript đơn giản (phù hợp để ghi trực tiếp vào cơ sở dữ liệu Firestore) thuộc loại DbModelType . Được sử 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 các FieldValues ​​như arrayUnion() được sử dụng làm giá trị thuộc tính. Nó 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ố

Tham số Kiểu Sự miêu tả
đối tượng mô hình Một phầnWithFieldValue <AppModelType>
tùy chọn Đặt tùy chọn

Trả về:

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