FirestoreDataConverter interface

Конвертер, используемый withConverter() для преобразования пользовательских объектов типа AppModelType в данные Firestore типа DbModelType .

Использование конвертера позволяет указывать аргументы универсального типа при хранении и извлечении объектов из Firestore.

В этом контексте «AppModel» — это класс, который используется в приложении для упаковки связанной информации и функций. Такой класс может, например, иметь свойства со сложными вложенными типами данных, свойства, используемые для запоминания, свойства типов, не поддерживаемых Firestore (таких как symbol и bigint ). ) и вспомогательные функции, выполняющие составные операции. Такие классы не подходят и/или невозможны для хранения в базе данных Firestore. Вместо этого экземпляры таких классов необходимо преобразовать в «простые старые объекты JavaScript» (POJO) с исключительно примитивными свойствами, потенциально вложенными внутри других POJO или массивов POJO. В этом контексте этот тип называется «DbModel» и может быть объектом, подходящим для сохранения в Firestore. Для удобства приложения могут реализовать FirestoreDataConverter и зарегистрировать преобразователь с помощью объектов Firestore, таких как DocumentReference или Query , чтобы автоматически преобразовать AppModel в DbModel при сохранении в Firestore и преобразовать DbModel в AppModel при извлечении из Firestore.

Подпись:

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

Методы

Метод Описание
fromFirestore(снимок, параметры) Вызывается Firestore SDK для преобразования данных Firestore в объект типа AppModelType . Вы можете получить доступ к своим данным, вызвав: snapshot.data(options) . Как правило, данные, возвращаемые из snapshot.data() могут быть преобразованы в DbModelType ; однако это не гарантируется, поскольку Firestore не применяет схему к базе данных. Например, запись из предыдущей версии приложения или запись из другого клиента, который не использовал преобразователь типов, могла записать данные с другими свойствами и/или типами свойств. Реализация должна будет выбрать, следует ли корректно восстановить несоответствующие данные или выдать ошибку. Чтобы переопределить этот метод, см.
toFirestore (модельОбъект) Вызывается Firestore SDK для преобразования пользовательского объекта модели типа AppModelType в простой объект JavaScript (подходящий для записи непосредственно в базу данных Firestore) типа DbModelType . Чтобы использовать set() с merge и mergeFields , toFirestore() должен быть определен с помощью PartialWithFieldValue<AppModelType> . Тип WithFieldValue<T> расширяет T , позволяя также использовать FieldValues, такие как deleteField(), в качестве значений свойств.
toFirestore (modelObject, параметры) Вызывается Firestore SDK для преобразования пользовательского объекта модели типа AppModelType в простой объект JavaScript (подходящий для записи непосредственно в базу данных Firestore) типа DbModelType . Используется с setDoc(). и с помощью merge:true или mergeFields . Тип PartialWithFieldValue<T> расширяет Partial<T> , позволяя использовать FieldValues, такие как arrayUnion(), в качестве значений свойств. Он также поддерживает вложенные Partial , позволяя опускать вложенные поля.

FirestoreDataConverter.fromFirestore()

Вызывается Firestore SDK для преобразования данных Firestore в объект типа AppModelType . Вы можете получить доступ к своим данным, вызвав: snapshot.data(options) .

Как правило, данные, возвращаемые из snapshot.data() можно преобразовать в DbModelType ; однако это не гарантируется, поскольку Firestore не применяет схему к базе данных. Например, запись из предыдущей версии приложения или запись из другого клиента, который не использовал преобразователь типов, могла записать данные с другими свойствами и/или типами свойств. Реализация должна будет выбрать, следует ли корректно восстановить несоответствующие данные или выдать ошибку.

Чтобы переопределить этот метод, см.

Подпись:

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

Параметры

Параметр Тип Описание
снимок Снимок документа запроса < Данные документа , Данные документа > QueryDocumentSnapshot содержащий ваши данные и метаданные.
параметры Параметры моментального снимка SnapshotOptions из первоначального вызова data() .

Возврат:

AppModelType

FirestoreDataConverter.toFirestore()

Вызывается Firestore SDK для преобразования объекта пользовательской модели типа AppModelType в простой объект JavaScript (подходящий для записи непосредственно в базу данных Firestore) типа DbModelType . Использование set() со merge и mergeFields , toFirestore() должен быть определен с помощью PartialWithFieldValue<AppModelType> .

Тип WithFieldValue<T> расширяет T , позволяя также использовать FieldValues, такие как deleteField(), в качестве значений свойств.

Подпись:

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

Параметры

Параметр Тип Описание
модельОбъект Сфилдвалуе <типмодели приложения>

Возврат:

Сфилдвалуе <ТипМоделиДб>

FirestoreDataConverter.toFirestore()

Вызывается Firestore SDK для преобразования объекта пользовательской модели типа AppModelType в простой объект JavaScript (подходящий для записи непосредственно в базу данных Firestore) типа DbModelType . Используется с setDoc(). и с помощью merge:true или mergeFields .

Тип PartialWithFieldValue<T> расширяет Partial<T> , позволяя использовать FieldValues, такие как arrayUnion(), в качестве значений свойств. Он также поддерживает вложенные Partial , позволяя опускать вложенные поля.

Подпись:

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

Параметры

Параметр Тип Описание
модельОбъект Частичносфилдвалуе <типмодели приложения>
параметры Установить параметры

Возврат:

Частичносфилдвалуе <ТипМоделиДб>

Пример

Простой пример

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

Расширенный пример

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