AppModelType
유형의 사용자 객체를 DbModelType
유형의 Firestore 데이터로 변환하기 위해 withConverter()
에서 사용하는 변환기 .
변환기를 사용하면 Firestore에서 객체를 저장하고 검색할 때 일반 유형 인수를 지정할 수 있습니다.
이러한 맥락에서 "AppModel"은 관련 정보와 기능을 함께 패키지하기 위해 애플리케이션에서 사용되는 클래스입니다. 예를 들어 이러한 클래스에는 복잡하고 중첩된 데이터 유형이 있는 속성, 메모에 사용되는 속성, Firestore에서 지원하지 않는 유형의 속성(예: symbol
및 bigint
이 있을 수 있습니다. ) 및 복합 연산을 수행하는 도우미 함수입니다. 이러한 클래스는 Firestore 데이터베이스에 저장하기에 적합하지 않거나 불가능합니다. 대신, 그러한 클래스의 인스턴스는 잠재적으로 다른 POJO 또는 POJO 배열 내에 중첩될 수 있는 기본 속성만 가진 "Plain Old JavaScript Objects"(POJO)로 변환되어야 합니다. 이 컨텍스트에서 이 유형은 'DbModel'이라고 하며 Firestore에 유지하는 데 적합한 객체입니다. 편의를 위해 애플리케이션은 FirestoreDataConverter
구현하고 DocumentReference
또는 Query
와 같은 Firestore 객체에 변환기를 등록할 수 있습니다. , Firestore에 저장할 때 AppModel
DbModel
로 자동 변환하고 Firestore에서 검색할 때 DbModel
AppModel
로 변환합니다.
서명:
export declare interface FirestoreDataConverter<AppModelType, DbModelType extends DocumentData = DocumentData>
행동 양식
방법 | 설명 |
---|---|
Firestore(스냅샷) | Firestore 데이터를 AppModelType 유형의 객체로 변환하기 위해 Firestore SDK에서 호출됩니다. snapshot.data() 호출하여 데이터에 액세스할 수 있습니다. 일반적으로 snapshot.data() 에서 반환된 데이터는 DbModelType 으로 캐스팅될 수 있습니다. 그러나 Firestore는 데이터베이스에 스키마를 적용하지 않기 때문에 이는 보장되지 않습니다. 예를 들어, 이전 버전의 애플리케이션에서 쓰기 또는 유형 변환기를 사용하지 않은 다른 클라이언트에서 쓰기는 다른 속성 및/또는 속성 유형을 사용하여 데이터를 썼을 수 있습니다. 구현에서는 부적합 데이터를 정상적으로 복구할지 아니면 오류를 발생시킬지 선택해야 합니다. |
toFirestore(모델객체) | AppModelType 유형의 커스텀 모델 객체를 DbModelType 유형의 일반 자바스크립트 객체(Firestore 데이터베이스에 직접 쓰는 데 적합)로 변환하기 위해 Firestore SDK에서 호출됩니다. setDoc() 과 함께 사용됩니다. , 그리고 . WithFieldValue<T> 유형은 T 확장하여 deleteField() 와 같은 FieldValues를 속성 값으로 사용할 수도 있습니다. |
toFirestore(modelObject, 옵션) | AppModelType 유형의 커스텀 모델 객체를 DbModelType 유형의 일반 자바스크립트 객체(Firestore 데이터베이스에 직접 쓰는 데 적합)로 변환하기 위해 Firestore SDK에서 호출됩니다. setDoc() 과 함께 사용됩니다. , 그리고 merge:true 또는 mergeFields 사용합니다. PartialWithFieldValue<T> 유형은 Partial<T> 확장하여 arrayUnion() 과 같은 FieldValues를 속성 값으로 사용할 수 있도록 합니다. 또한 중첩된 필드를 생략할 수 있도록 하여 중첩된 Partial 도 지원합니다. |
FirestoreDataConverter.fromFirestore()
Firestore 데이터를 AppModelType
유형의 객체로 변환하기 위해 Firestore SDK에서 호출됩니다. . snapshot.data()
호출하여 데이터에 액세스할 수 있습니다. .
일반적으로 snapshot.data()
에서 반환된 데이터는 DbModelType
으로 캐스팅될 수 있습니다. ; 그러나 Firestore는 데이터베이스에 스키마를 적용하지 않기 때문에 이는 보장되지 않습니다. 예를 들어, 이전 버전의 애플리케이션에서 쓰기 또는 유형 변환기를 사용하지 않은 다른 클라이언트에서 쓰기는 다른 속성 및/또는 속성 유형을 사용하여 데이터를 썼을 수 있습니다. 구현에서는 부적합 데이터를 정상적으로 복구할지 아니면 오류를 발생시킬지 선택해야 합니다.
서명:
fromFirestore(snapshot: QueryDocumentSnapshot<DocumentData, DocumentData>): AppModelType;
매개변수
매개변수 | 유형 | 설명 |
---|---|---|
스냅 사진 | 쿼리문서스냅샷 < 문서데이터 , 문서데이터 > | 데이터와 메타데이터가 포함된 QueryDocumentSnapshot . |
보고:
앱모델 유형
FirestoreDataConverter.toFirestore()
AppModelType
유형의 커스텀 모델 객체를 DbModelType
유형의 일반 자바스크립트 객체(Firestore 데이터베이스에 직접 쓰는 데 적합)로 변환하기 위해 Firestore SDK에서 호출됩니다. . setDoc() 과 함께 사용됩니다. , 그리고 .
WithFieldValue<T>
유형은 T
확장하여 deleteField() 와 같은 FieldValues를 속성 값으로 사용할 수도 있습니다.
서명:
toFirestore(modelObject: WithFieldValue<AppModelType>): WithFieldValue<DbModelType>;
매개변수
매개변수 | 유형 | 설명 |
---|---|---|
모델객체 | 필드값 포함 <앱모델 유형> |
보고:
필드값 포함 <Db모델 유형>
FirestoreDataConverter.toFirestore()
AppModelType
유형의 커스텀 모델 객체를 DbModelType
유형의 일반 자바스크립트 객체(Firestore 데이터베이스에 직접 쓰는 데 적합)로 변환하기 위해 Firestore SDK에서 호출됩니다. . setDoc() 과 함께 사용됩니다. , 그리고 merge:true
또는 mergeFields
사용 .
PartialWithFieldValue<T>
유형은 Partial<T>
확장하여 arrayUnion() 과 같은 FieldValues를 속성 값으로 사용할 수 있도록 합니다. 또한 중첩된 필드를 생략할 수 있도록 하여 중첩된 Partial
도 지원합니다.
서명:
toFirestore(modelObject: PartialWithFieldValue<AppModelType>, options: SetOptions): PartialWithFieldValue<DbModelType>;
매개변수
매개변수 | 유형 | 설명 |
---|---|---|
모델객체 | PartialWithFieldValue <앱모델 유형> | |
옵션 | 옵션 설정 |
보고:
PartialWithFieldValue <Db모델 유형>
예
간단한 예
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');
}
}