โค้ดไคลเอ็นต์สามารถสมัครรับข้อมูลการค้นหาเพื่อรับข้อมูลอัปเดตแบบเรียลไทม์เมื่อ ผลลัพธ์ของการค้นหามีการเปลี่ยนแปลง
ก่อนเริ่มต้น
ตั้งค่าการสร้าง SDK สำหรับโปรเจ็กต์ตามที่อธิบายไว้ในเอกสารประกอบสำหรับเว็บ แพลตฟอร์ม Apple และ Flutter
- คุณต้องเปิดใช้การแคชฝั่งไคลเอ็นต์สำหรับ SDK ทั้งหมดที่สร้างขึ้น กล่าวคือ การกำหนดค่า SDK ทุกรายการต้องมีการประกาศดังต่อไปนี้
clientCache: maxAge: 5s storage: ... # Optional.ไคลเอ็นต์แอปของคุณต้องใช้ SDK หลักของ SQL Connect เวอร์ชันล่าสุด
- Apple: Firebase SQL Connect SDK สำหรับ Swift เวอร์ชัน 11.12.0 ขึ้นไป
- เว็บ: JavaScript SDK เวอร์ชัน 12.12.0 ขึ้นไป
- Flutter:
firebase_data_connectเวอร์ชัน 0.3.0 ขึ้นไป
สร้าง SDK ของไคลเอ็นต์ใหม่โดยใช้ Firebase CLI เวอร์ชัน 15.14.0 ขึ้นไป
การติดตามผลการค้นหา
คุณสามารถติดตามการค้นหาเพื่อตอบสนองต่อการเปลี่ยนแปลงในผลการค้นหา เช่น สมมติว่าคุณมีสคีมาและการดำเนินการต่อไปนี้ที่กำหนดไว้ในโปรเจ็กต์
# dataconnect/schema/schema.gql
type Movie @table(key: "id") {
id: UUID! @default(expr: "uuidV4()")
title: String!
releaseYear: Int
genre: String
description: String
averageRating: Int
}
# dataconnect/connector/operations.gql
query GetMovieById($id: UUID!) @auth(level: PUBLIC) {
movie(id: $id) {
id
title
releaseYear
genre
description
}
}
mutation UpdateMovie(
$id: UUID!,
$genre: String!,
$description: String!
) {
movie_update(id: $id,
data: {
genre: $genre
description: $description
})
}
หากต้องการติดตามการเปลี่ยนแปลงในผลลัพธ์ของการเรียกใช้ GetMovieById ให้ทำดังนี้
เว็บ
import { subscribe, DataConnectError, QueryResult } from 'firebase/data-connect';
import { getMovieByIdRef, GetMovieByIdData, GetMovieByIdVariables } from '@dataconnect/generated';
const queryRef = getMovieByIdRef({ id: "<MOVIE_ID>" });
// Called when receiving an update.
const onNext = (result: QueryResult<GetMovieByIdData, GetMovieByIdVariables>) => {
console.log("Movie <MOVIE_ID> updated", result);
}
const onError = (err?: DataConnectError) => {
console.error("received error", err);
}
// Called when unsubscribing or when the subscription is automatically released.
const onComplete = () => {
console.log("subscription complete!");
}
const unsubscribe = subscribe(queryRef, onNext, onError, onComplete);
เว็บ (React)
import { subscribe, QueryResult } from 'firebase/data-connect';
import { getMovieByIdRef, GetMovieByIdData, GetMovieByIdVariables } from '@dataconnect/generated';
import { useState, useEffect } from "react";
export const MovieInfo = ({ id: movieId }: { id: string }) => {
const [movieInfo, setMovieInfo] = useState<GetMovieByIdData>();
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
const queryRef = getMovieByIdRef({ id: movieId });
function updateUi(result: QueryResult<GetMovieByIdData, GetMovieByIdVariables>): void {
setMovieInfo(result.data);
setLoading(false);
}
const unsubscribe = subscribe(
queryRef,
updateUi,
(err) => {
setError(err ?? new Error("Unknown error occurred"));
setLoading(false);
}
);
return () => unsubscribe();
}, [movieId]);
if (loading)
return <div>Loading movie details...</div>;
if (error || !movieInfo || !movieInfo.movie)
return <div>Error loading movie details: {error?.message}</div>;
return (
<div>
<h2>{movieInfo.movie.title} ({movieInfo.movie.releaseYear})</h2>
<ul>
<li>Genre: {movieInfo.movie.genre}</li>
<li>Description: {movieInfo.movie.description}</li>
</ul>
</div>
);
};
SQL Connect ยังรองรับการแคชและการสมัครใช้บริการแบบเรียลไทม์โดยใช้
TanStack เมื่อคุณระบุ react: true หรือ angular: true ในไฟล์ connector.yaml SQL Connect จะสร้างการเชื่อมโยงสำหรับ React หรือ Angular โดยใช้ TanStack
การเชื่อมโยงเหล่านี้สามารถทำงานร่วมกับ SQL Connectการสนับสนุนแบบเรียลไทม์ในตัวได้ แต่จะทำได้เฉพาะในกรณีที่ มีความยากลำบากบางอย่างเท่านั้น เราขอแนะนำให้คุณใช้การเชื่อมโยงที่อิงตาม TanStack หรือSQL Connectการสนับสนุนแบบเรียลไทม์ในตัว แต่ไม่ใช่ทั้ง 2 อย่าง
โปรดทราบว่าการติดตั้งใช้งานแบบเรียลไทม์ของ SQL Connect เองมีข้อดีบางประการเหนือการเชื่อมโยง TanStack ดังนี้
- การแคชที่แปลงเป็นรูปแบบมาตรฐาน: SQL Connect ใช้การแคชที่แปลงเป็นรูปแบบมาตรฐาน ซึ่งช่วยปรับปรุงความสอดคล้องของข้อมูล รวมถึงประสิทธิภาพของหน่วยความจำและเครือข่าย เมื่อเทียบกับการแคชระดับการค้นหา เมื่อใช้การแคชที่ปรับให้เป็นมาตรฐาน หากเอนทิตี อัปเดตในส่วนหนึ่งของแอป เอนทิตีนั้นก็จะอัปเดตในส่วนอื่นๆ ที่ใช้เอนทิตีนั้นด้วย
- การทำให้เป็นโมฆะจากระยะไกล: SQL Connect ทำให้เอนทิตีที่แคชไว้เป็นโมฆะจากระยะไกล ในอุปกรณ์ที่สมัครใช้บริการทั้งหมดได้
หากเลือกไม่ใช้ TanStack คุณควรนำการตั้งค่า react: true และ
angular: true ออกจากไฟล์ connector.yaml
iOS
struct ListMovieView: View {
// QueryRef has the Observable attribute, so its properties will
// automatically trigger updates on changes.
private var queryRef = connector.listMoviesByGenreQuery.ref(genre: "Sci-Fi")
// Store the handle to unsubscribe from query updates.
@State private var querySub: AnyCancellable?
var body: some View {
VStack {
// Use the query results in a View.
ForEach(queryRef.data?.movies ?? [], id: \.self.id) { movie in
Text(movie.title)
}
}
.onAppear {
// Subscribe to the query for updates using the Observable macro.
Task {
do {
querySub = try await queryRef.subscribe().sink { _ in }
} catch {
print("Error subscribing to query: \(error)")
}
}
}
.onDisappear {
querySub?.cancel()
}
}
}
Flutter
นำเข้า SDK ที่สร้างขึ้นของโปรเจ็กต์
import 'package:flutter_app/dataconnect_generated/generated.dart';
จากนั้นเรียกใช้เมธอด subscribe() ในการอ้างอิงการค้นหา
final queryRef = MovieConnector.instance.getMovieById(id: "<MOVIE_ID>").ref();
final subscription = queryRef.subscribe().listen((result) {
final movie = result.data.movie;
if (movie != null) {
// Execute your logic to update the UI with the refreshed movie information.
updateUi(movie.title);
}
});
หากต้องการหยุดรับข้อมูลอัปเดต คุณสามารถโทรหา subscription.cancel()
เมื่อสมัครรับข้อมูลการค้นหาตามตัวอย่างก่อนหน้าแล้ว คุณจะได้รับการอัปเดตทุกครั้งที่ผลลัพธ์ของการค้นหาที่เฉพาะเจาะจงเปลี่ยนแปลง ตัวอย่างเช่น หากไคลเอนต์อื่นเรียกใช้การกลายพันธุ์ UpdateMovie ในรหัสเดียวกันกับที่คุณสมัครรับข้อมูล คุณจะได้รับการอัปเดต
สัญญาณการรีเฟรชคำค้นหาโดยนัย
ในตัวอย่างก่อนหน้า คุณสามารถติดตามการค้นหาและรับข้อมูลอัปเดตแบบเรียลไทม์ได้โดยไม่ต้องแก้ไขการดำเนินการใดๆ เพิ่มเติม โดยเฉพาะอย่างยิ่ง คุณไม่จำเป็นต้องระบุว่าUpdateMovieการเปลี่ยนแปลงGetMovieByIdอาจส่งผลต่อผลลัพธ์ของคำค้นหา GetMovieById
ซึ่งเป็นไปได้เนื่องจากคำค้นหา GetMovieById จะได้รับการรีเฟรชโดยนัย
จากสัญญาณการเปลี่ยนแปลง UpdateMovie ระบบจะส่งสัญญาณรีเฟรชโดยนัย
ระหว่างชุดย่อยของการค้นหาและการเปลี่ยนแปลงที่คุณอาจเขียน
หากการค้นหาของคุณทําการค้นหาเอนทิตีเดียวตามคีย์หลัก การเปลี่ยนแปลงใดๆ ที่เขียนไปยังเอนทิตีเดียวกันซึ่งระบุด้วยคีย์หลักจะทําให้เกิดสัญญาณรีเฟรชโดยนัย
_insertและ_insertMany_upsertและ_upsertMany_update_delete
_deleteMany และ _updateMany ไม่ส่งสัญญาณรีเฟรช
ในตัวอย่างก่อนหน้า คำค้นหา GetMovieById จะค้นหาภาพยนตร์เรื่องเดียวตามรหัส
(movie(id: $id)) และการเปลี่ยนแปลง UpdateMovie จะอัปเดตภาพยนตร์เรื่องเดียว
ที่ระบุโดยรหัส (movie_update(id: $id, ...)) ดังนั้นคำค้นหาจึงใช้ประโยชน์
จากการรีเฟรชโดยนัยได้
การดำเนินการแทรกและอัปเดตสามารถทริกเกอร์สัญญาณการรีเฟรชโดยนัยได้เมื่อคุณ ใช้ค่าที่ทราบ เช่น Firebase Authentication UID ของผู้ใช้
ตัวอย่างเช่น ลองพิจารณาคำค้นหาต่อไปนี้
query GetExtendedProfileByUser @auth(level: USER) {
profile(key: { id_expr: "auth.uid" }) {
id
status
photoUrl
socialLink
}
}
การค้นหาจะได้รับสัญญาณรีเฟรชโดยนัยจากการเปลี่ยนแปลง เช่น การเปลี่ยนแปลงต่อไปนี้
mutation UpsertExtendedProfile($status: String, $photoUrl: String, $socialLink: String) @auth(level: USER) {
profile_upsert(
data: {
id_expr: "auth.uid"
status: $status
photoUrl: $photoUrl
socialLink: $socialLink
}
) {
id
status
photoUrl
socialLink
}
}
เมื่อการค้นหาหรือการเปลี่ยนแปลงมีความซับซ้อนมากขึ้น คุณจะต้อง ระบุเงื่อนไขที่ต้องมีการรีเฟรชการค้นหา ไปที่ส่วนถัดไปเพื่อดูวิธี
สัญญาณการรีเฟรชการค้นหาที่ชัดเจน
นอกเหนือจากสัญญาณการรีเฟรชที่ส่งโดยการเปลี่ยนแปลงไปยัง
การค้นหาโดยนัยแล้ว คุณยังระบุได้อย่างชัดเจนว่าเมื่อใดที่การค้นหาควรได้รับสัญญาณ
การรีเฟรช ซึ่งทำได้โดยการใส่คำอธิบายประกอบในคำค้นหาด้วยคำสั่ง @refresh
คุณต้องใช้@refreshเมื่อใดก็ตามที่คำค้นหาไม่เป็นไปตามเกณฑ์ที่เฉพาะเจาะจง (ดูด้านบน) สำหรับการรีเฟรชอัตโนมัติ ตัวอย่างคำค้นหาที่ต้องมีคำสั่งนี้ ได้แก่
- คำค้นหาที่ดึงข้อมูลรายการเอนทิตี
- การค้นหาที่ทำการรวมในตารางอื่นๆ
- คำค้นหาการรวม
- การค้นหาที่ใช้ SQL เนทีฟ
- การค้นหาที่ใช้ตัวแก้ไขที่กำหนดเอง
คุณระบุนโยบายการรีเฟรชได้ 2 วิธีดังนี้
ช่วงเวลาตามเวลา
รีเฟรชการค้นหาในช่วงเวลาคงที่
ตัวอย่างเช่น สมมติว่าฐานผู้ใช้ที่ใช้งานอย่างสม่ำเสมอทำให้ระบบอัปเดตคะแนนสะสมของภาพยนตร์หลายครั้งทุกนาที โดยเฉพาะหลังจากที่ภาพยนตร์ออกฉาย คุณสามารถรีเฟรชคําค้นหาทุกๆ 2-3 วินาทีแทนที่จะรีเฟรชทุกครั้งที่การจัดอันดับเปลี่ยนแปลง เพื่อรับข้อมูลอัปเดตที่แสดงผลลัพธ์สะสมของการเปลี่ยนแปลงที่อาจเกิดขึ้นหลายครั้ง
# dataconnect/connector/operations.gql
query GetMovieRating($id: UUID!) @auth(level: PUBLIC) @refresh(every: {seconds: 30}) {
movie(id: $id) {
id
averageRating
}
}
การดำเนินการกลายพันธุ์
รีเฟรชการค้นหาเมื่อมีการดำเนินการการเปลี่ยนแปลงที่เฉพาะเจาะจง แนวทางนี้จะระบุอย่างชัดเจนว่าการเปลี่ยนแปลงใดที่มีโอกาสเปลี่ยนผลลัพธ์ของการค้นหา
เช่น สมมติว่าคุณมีคำค้นหาที่ดึงข้อมูลเกี่ยวกับภาพยนตร์หลายเรื่องแทนที่จะเป็นภาพยนตร์เรื่องใดเรื่องหนึ่ง การค้นหานี้ควรรีเฟรชทุกครั้งที่การเปลี่ยนแปลง อัปเดตระเบียนภาพยนตร์
query ListMovies($offset: Int)
@auth(level: PUBLIC, insecureReason: "Anyone can list all movies.")
@refresh(onMutationExecuted: { operation: "UpdateMovie" }) {
movies(limit: 10, offset: $offset) {
id
title
releaseYear
genre
description
}
}
นอกจากนี้ คุณยังระบุเงื่อนไขนิพจน์ CEL ที่ต้องเป็นไปตามข้อกำหนดเพื่อให้การ เปลี่ยนแปลงทริกเกอร์การรีเฟรชการค้นหาได้ด้วย
เราขอแนะนำให้ทำเช่นนั้น ยิ่งระบุเงื่อนไขได้แม่นยำมากเท่าใด ระบบก็จะใช้ทรัพยากรฐานข้อมูลที่ไม่จำเป็นน้อยลง และแอปก็จะตอบสนองได้ดีมากขึ้น
ตัวอย่างเช่น สมมติว่าคุณมีคำค้นหาที่ แสดงภาพยนตร์เฉพาะในประเภทที่ระบุ การค้นหานี้ควรรีเฟรชเมื่อการเปลี่ยนแปลงอัปเดตภาพยนตร์ในประเภทเดียวกันเท่านั้น
query ListMoviesByGenre($genre: String, $offset: Int)
@auth(level: PUBLIC, insecureReason: "Anyone can list movies.")
@refresh(onMutationExecuted: {
operation: "UpdateMovie",
condition: "request.variables.genre == mutation.variables.genre"
}) {
movies(
where: { genre: { eq: $genre } },
limit: 10,
offset: $offset) {
id
title
releaseYear
genre
description
}
}
การเชื่อมโยง CEL ในเงื่อนไข @refresh
condition นิพจน์ใน onMutationExecuted มีสิทธิ์เข้าถึงบริบท 2 อย่าง ได้แก่
request
สถานะของคำค้นหาที่กำลังติดตาม
| การเชื่อมโยง | คำอธิบาย |
|---|---|
request.variables |
ตัวแปรที่ส่งไปยังการค้นหา (เช่น request.variables.id) |
request.auth.uid |
Firebase Authentication UID ของผู้ใช้ที่เรียกใช้การค้นหา |
request.auth.token |
พจนานุกรมของFirebase Authenticationการอ้างสิทธิ์โทเค็นสำหรับผู้ใช้ที่เรียกใช้คําค้นหา |
mutation
สถานะของการเปลี่ยนแปลงที่ดำเนินการ
| การเชื่อมโยง | คำอธิบาย |
|---|---|
mutation.variables |
ตัวแปรที่ส่งไปยังการกลายพันธุ์ (เช่น mutation.variables.movieId) |
mutation.auth.uid |
Firebase Authentication UID ของผู้ใช้ที่ดำเนินการกลายพันธุ์ |
mutation.auth.token |
พจนานุกรมของFirebase Authenticationการอ้างสิทธิ์โทเค็นสำหรับผู้ใช้ที่ดำเนินการกลายพันธุ์ |
รูปแบบทั่วไป
# Refresh only when the mutation targets the same entity
"request.variables.id == mutation.variables.id"
# Refresh only when the same user who subscribed makes a change
"request.auth.uid == mutation.auth.uid"
# Refresh when a specific field value matches a condition
"request.auth.uid == mutation.auth.uid && mutation.variables.status == 'PUBLISHED'"
# Refresh when a specific flag is set in the mutation
"mutation.variables.isPublic == true"
คำสั่ง @refresh หลายรายการ
คุณระบุคำสั่ง @refresh หลายครั้งในคำค้นหาเพื่อทริกเกอร์การรีเฟรชเมื่อใดก็ตามที่มีการตรงตามเกณฑ์ใดเกณฑ์หนึ่งที่ระบุโดยคำสั่ง @refresh
เช่น การค้นหาต่อไปนี้จะรีเฟรชทุกๆ 30 วินาที รวมถึง เมื่อใดก็ตามที่มีการดำเนินการกลายพันธุ์ที่ระบุ
query ListMovies($offset: Int)
@auth(level: PUBLIC, insecureReason: "Anyone can list all movies.")
@refresh(every: {seconds: 30})
@refresh(onMutationExecuted: { operation: "UpdateMovie" })
@refresh(onMutationExecuted: { operation: "BulkUpdateMovies" }) {
movies(limit: 10, offset: $offset) {
id
title
releaseYear
genre
description
}
}
ข้อมูลอ้างอิง
ดูตัวอย่างเพิ่มเติมได้ที่@refreshการอ้างอิงคำสั่ง