Firestore의transaction 사용 방법 및 사용 방법
네, 그것도 좋아요.
다음은Firestore의transaction(이하 거래라고 부른다)의 기능과 구체적인 예를 사용한 자바스크립트의 코드와 보안 규칙을 쓰는 방법을 소개한다.
독자 대상
주로 사무라는 단어에 익숙하지 않은 초보자를 대상으로 한다.
후반부 거래 사용 시 안전 규칙의 작성은 중급자도 참고할 수 있다고 생각합니다.
컨디션
Firestore 거래를 구성하는 요소
파이어스토어의 거래에는 크게 두 가지 요소가 포함돼 있다.
여러 문서에 통합 쓰기
여러 문서의 대량 쓰기 기능은 여러 문서를 작성할 때 모든 문서가 기록되거나 기록되지 않도록 합니다.반달구지 상태가 기록되는 것을 방지하는 기능이라는 얘기다.
로큰롤의 사용 예로, 예를 들면 EC 사이트에서 상품이 잘 팔릴 때를 고려할 때.이때'상품 재고 감소','주문 정보 쓰기'두 가지 처리 방법이 있다.쓰기 중 오류가 발생하면 이전에 변경한 내용이 무시됩니다.거래를 이용하면 재고가 줄어들었지만 주문 정보가 없거나 상반되는 상황이 발생하지 않을 수 있다.
잠금(배타 제어)
잠금(배타적 제어)이란 여러 사용자가 문서를 조작할 때 한 사용자만 편집할 수 있는 기능을 말한다.
록 음악의 사용 예로 예를 들면 EC 사이트에서 상품이 잘 팔릴 때의 일을 다시 한 번 고려한다.A와 B가 재고품 10개 상품 5개, 3개를 동시에 샀다고 가정하자.이때 최종 재고수는 2개일 것이다.
자물쇠를 사용하지 않고 시기가 좋지 않으면 다음과 같이 재고와 일치하지 않습니다.
이거 막아. 록이야.자물쇠를 사용하면 두 사용자가 거의 동시에 업데이트를 하더라도 한 쪽이 끝난 후에 다른 쪽이 업데이트를 할 수 있습니다.
로큰롤의 실시 방식에는 비관적인 로큰롤과 낙관적인 로큰롤이 있다.Firestore의 웹 SDK(브라우저의 자바스크립트로 이동하면)는 낙관적인 록을 채택했다.두 가지 로큰롤의 이미지로 대충 전달된다.(이미지이기 때문에 실제 설치와 다름)
비관 록
비관 록은 데이터를 읽을 때 다른 사용자가 읽기와 쓰기를 금지하는 방식이다.
낙관 록
낙관적인 록은 데이터를 읽을 때 미리 내용을 저장하고 업데이트할 때 읽은 데이터를 업데이트 전의 값과 비교하며 차이가 없으면 기록하는 방법이다.
RDB(관계 데이터베이스)에서 대부분의 경우 여러 문서의 대량 쓰기를'사무'라고 부른다.잠금 정보는 잠금 또는 트랜잭션 분리 레벨의 컨텍스트에서 설명됩니다.
트랜잭션 사용 예
번호판 발행 프로그램
예를 들어 번호판을 발행하는 프로그램을 고려해 보자.
사용자가 "번호표 취득"단추를 눌렀을 때
데이터 구조는 이렇다.
번호표를 받았을 때 그랬어요.
사무의 실현
번호표 획득 버튼이 눌렸을 때 진행된 일은 다음과 같다.
트랜잭션 준비 작업
Firebase 연결의 초기화는 다음과 같습니다.
firebase.js
import { initializeApp } from "firebase/app"
import { getAuth } from "firebase/auth"
import { getFirestore } from "firebase/firestore"
// ここの設定は自身の設定に置き換える
const firebaseConfig = {
apiKey: "xxxxxxxxxxxxxxxxxxxx",
authDomain: "xxxxxxxxxxx.firebaseapp.com",
projectId: "xxxxxxxxxxx",
storageBucket: "xxxxxxxxxxx.appspot.com",
messagingSenderId: "xxxxxxxxxxxxxxxxxx",
appId: "xxxxxxxxxxxxxxxxxxxx"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig)
export const auth = getAuth()
export const db = getFirestore()
사무 기능을 사용하려면 먼저 호출runTransaction()
하십시오.import { doc, runTransaction } from "firebase/firestore"
import { db, auth } from "./firebase"
const EventTicket = () => {
const ticketEventId = "xxx"
const handleIssueTicket = async () => {
await runTransaction(db, async (transaction) => {
// TODO ここにトランザクションの内容を書く
})
}
return (
<button onClick={handleIssueTicket}>整理券を取得する</button>
)
}
export default EventTicket
잠금(배타 제어)을 위한 업데이트 전 값 수신
transaction.get()
를 사용하여 문서를 읽고 잠급니다. const handleIssueTicket = async () => {
await runTransaction(db, async (transaction) => {
// 更新前の値を取得
const ticketEventsDocRef = doc(db, "ticket-events", ticketEventId)
const ticketEventsDocSnap = await transaction.get(ticketEventsDocRef)
if (!ticketEventsDocSnap.exists()) {
throw "ticketEvent document does not exist!"
}
})
}
문서 업데이트
사무 업데이트 문서
transaction.update()
를 사용하여 문서를 작성transaction.set()
합니다. const handleIssueTicket = async () => {
await runTransaction(db, async (transaction) => {
// 更新前の値を取得
const ticketEventsDocRef = doc(db, "ticket-events", ticketEventId)
const ticketEventsDocSnap = await transaction.get(ticketEventsDocRef)
if (!ticketEventsDocSnap.exists()) {
throw "ticketEvent document does not exist!"
}
const ticketNum = ticketEventsDocSnap.data().nextTicketNum
// nextTicketNumを更新
transaction.update(ticketEventsDocRef, { nextTicketNum: ticketNum + 1, })
// 整理券を作成
const ticketDocRef = doc(db, "ticket-events", ticketEventId, "tickets", String(ticketNum))
transaction.set(ticketDocRef, {
user: auth.currentUser.uid,
})
})
}
이상의 JavaScript 측면 설치가 완료되었습니다.Firestore는 거래를 사용하지 않는 것과 비슷한 코드로 작성할 수 있어 편리하다.거래 중 보안 규칙 업데이트 보장
거래에서 업데이트를 진행하여 일치하지 않는 것을 피하려면 보안 규칙에 같은 내용을 써서 불법 방문으로 인한 데이터의 일치하지 않도록 하십시오.
정리권 받을 때.
이것을 안전 규칙에 써라.
일단 틀부터 준비해.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /ticket-events/{ticketEvent} {
// TODO ここにticket-eventsの条件を書く
match /tickets/{ticket} {
// TODO ここにticketsの条件を書く
}
}
}
}
그리고 업무를 수행할 때rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /ticket-events/{ticketEvent} {
allow get: if true;
allow create: if request.auth != null && request.auth.uid == request.resource.data.owner;
allow update: if request.auth != null &&
request.resource.data.diff(resource.data).affectedKeys().hasOnly(["nextTicketNum"]) &&
request.resource.data.nextTicketNum == resource.data.nextTicketNum + 1 &&
request.auth.uid == getAfter(
/databases/$(database)/documents/ticket-events/$(ticketEvent)/tickets/$(resource.data.nextTicketNum)
).data.user;
match /tickets/{ticket} {
// TODO ここにticketsの条件を書く
}
}
}
}
규칙을 해설하다.request.resource.data.diff(resource.data).affectedKeys().hasOnly(["nextTicketNum"])
에 업데이트 대상의 필드가 포함되지 않음nextTicketNum
의외입니다.request.resource.data.nextTicketNum == resource.data.nextTicketNum + 1
에서 갱신nextTicketNum
할 때 보증치는 반드시 1 증가합니다.getAfter(path)
함수는 거래가 끝났을 때path
의 내용을 되돌려줍니다.request.auth.uid == getAfter(/databases/$(database)/documents/ticket-events/$(ticketEvent)/tickets/$(resource.data.nextTicketNum)).data.user
에서 거래가 완료되었을 때 이ticketEvent의 /tickets/{更新前のnextTicketNum}
user는 로그인한 사용자의 id와 같습니다.rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /ticket-events/{ticketEvent} {
// 上と同じ
match /tickets/{ticket} {
allow create: if request.auth != null && request.auth.uid == request.resource.data.user &&
int(request.resource.id) > 0 &&
request.resource.id == string(
getAfter(
/databases/$(database)/documents/ticket-events/$(ticketEvent)
).data.nextTicketNum - 1
);
}
}
}
}
규칙을 해설하다.사용자가
request.auth != null && request.auth.uid == request.resource.data.user
에 로그인하고 번호판의 사용자와 로그인한 사용자의 id가 같음을 보증합니다.int(arg)
함수는 매개 변수를 정수로 변환합니다.request.resource.id
는 새 문서의 ID입니다.보증
int(request.resource.id) > 0
에 작성된 문서의 ID가 0보다 큽니다.string(arg)
함수는 매개 변수를 문자열로 변환합니다.getAfter(path)
함수는 거래가 끝났을 때path
의 내용을 되돌려줍니다.getAfter(/databases/$(database)/documents/ticket-events/$(ticketEvent)).data.nextTicketNum
거래 종료 시 부모 문서nextTicketNum
를 받습니다.request.resource.id == string(getAfter(/databases/$(database)/documents/ticket-events/$(ticketEvent)).data.nextTicketNum - 1)
에서 부모 문서가 업데이트된 값에서 1을 빼고 문자열로 변환하면 ticket의 문서 ID와 같습니다.끝맺다
번호표 응용 프로그램은 필자가 실제로 제작한 응용 프로그램이다.가능하면 이쪽 기사도 주세요.
Reference
이 문제에 관하여(Firestore의transaction 사용 방법 및 사용 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://zenn.dev/yucatio/articles/7c4ba0d0138ca9텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)