-
이제 Database에 데이터를 추가하고, 수정하고, 삭제하는 법을 알아보자.
서론: 데이터 수정의 기준
데이터를 불러와서 보여줄 때는 통째로 불러와 내가 만든 배열에 넣고 순서를 정렬해서 보여주면 됐다.
그 중 어떤 데이터를 선택해서 그 데이터의 상세 데이터를 볼 때도 내가 코딩한 배열만 신경 쓰면 됐다.
데이터를 불러온 순간부터는 내 배열만 신경쓰면 되는 것이었다.
물론 거기에 필터링이 들어가고 하면 다르지만, 일단 그건 차치하고.
이와 달리 데이터를 쓰고 수정할 때는 정확히 어떤 데이터를 어떤 위치에 쓸 것인지 기준을 줘야 한다.
사실 이는 데이터 베이스를 만들 때부터 데이터들을 어떻게 관리해 나갈지의 가장 기초적인 문제일 것이다.
예를 들어, 아이템들을 사람 이름처럼 String으로 구분할 수도 있겠지만
정말 사람 이름처럼 동명이인이 있을 수도 있고, 새로 아이템을 만들 때도 규칙적인 String을 끊임없이 만들어 내는 데 한계가 있을 수 있다.
그래서 아이템들을 고유하게 구분할 수 있는 것을 기준점으로 삼아 아이템을 추가하고, 수정/삭제할 수 있도록 해야 한다.
앞서 예시로 보여줬던 database의 item들은 아래와 같이 고유 아이디로서 "id"를 부여해 구분했다.
따라서 모바일 화면에서 아이템을 선택하면 Database에서 이 선택한 아이템의 id와 같은 id의 item을 명확하게 뽑아낼 수 있다.
새로운 아이템을 추가할 때는 코드 내에서 직접 count 변수를 만들어 추가할 때마다 count를 하나씩 더해서 id를 부여해도 될 것이다.
데이터가 삭제되는 시스템이 아니라면 배열상수를 카운트해서 줄 수도 있겠다.
본론: 데이터 수정하기
Step0. 변수 Review
앞에서 데이터를 불러오는 작업을 했으므로 데이터 수정을 위한 모든 준비가 다 완료되었지만
그래도 데이터 수정을 위해 어떤 것이 세팅되어있어야 하는지 살펴볼 필요가 있다.
데이터 수정은 데이터 root에 접근하면 되므로 아래의 세팅까지만 준비되어 있으면 된다.
(1) DatabaseReference 타입의 변수를 하나 선언하고,
var ref: DatabaseReference!
(2) 이 변수로 database의 root에 접근한다.
ref = Database.database().reference()
여기까지가 데이터를 수정하기 위해 세팅된 것들이다.
수정 작업은 이 ref에서 명령어를 추가하여 이루어진다.
다만 여기서도 선택할 수 있는 옵션이 있다.
(case1) 첫번째는 아래처럼 가장 상위의 데이터들의 이름을 알 때이고,
(case2) 두번째는 반대로 이를 모를 때, 또는 알 수 없을 때이다.
당연히 case1의 방법이 더 쉽지만 데이터의 이름은 난수로 만들어지는 케이스도 꽤 많다고 하니 후자의 중요성이 더 중요할 수도 있다.
하나씩 step으로 살펴보자.
step1. 기준점이 되는 값 준비하기
let cardID = cardList[indexPath.row].id
예시에서는 내가 화면에서 선택한 아이템의 id를 준비했다. database에서 이 id와 똑같은 Data를 지명할 것이다.
step2. 데이터 추가 / 수정하기
(case1)
이 경우는 명령어만 기억하면 된다.
child 명령어에 string 형식으로 path를 입력하는데, 상위 카테고리명을 알고 있으니 아래처럼 입력인 간단하다.
여기에 setValue로 값을 설정/수정하면 된다.
ref.child("Item\(cardID)/isSelected").setValue(true)
위 예시에서는 아이템의 넘버와 cardID가 같아 child 명령어로 path를 지정한 예시이다.
(case2)
하지만 앞서 말했든 이를 파악할 수 없을 때가 더 많다.
이럴 때도 일단 기준점은 step1에서 잡은 cardID이고, database의 내용을 정리해서 이와 같은 id의 아이템을 잡아낼 것이다.
꼭 잡아낼 것이다.
ref.queryOrdered(byChild: "id").queryEqual(toValue: cardID).observe(.value) { [weak self] snapshot in print(snapshot) guard let self = self, let value = snapshot.value as? [String: [String: Any]], let key = value.keys.first else { return } self.ref.child("\(key)/isSelected").setValue(true) }
우선 살펴보면 데이터 베이스를 불러올 때와 마찬가지로 snapshot이 필요하고, 마지막에는 (case1)가 거의 동일하다.
결국은 알 수 없는 이름을 찾아내어 그걸 path로 쓰는 것이다.
첫번째 줄부터 차큰차큰 살펴보면
(1) queryOrdered(byChild: "id") : id로 아이템 찾을 거야.
(2) queryEqual(toValue: cardID) : id의 값이 위에서 만든 cardID와 같은 게 내가 찾는 거야.
(3) observe(.value) { ~ snapshot : 그 데이터 snapshot 좀 보자
이제 스냅샷에서 case1처럼 카테고리의 제일 상단에 있을 그 놈을 지정해주면 된다.
참고로, step 제목을 수정/추가라고 한 이유는 child 명령어가 입력한 path가 있으면 수정, 없으면 생성 방식으로 작동하기 때문이다.
step3. 데이터 삭제하기
데이터 삭제도 수정하기와 마찬가지로 path String을 알 때와 모를 때 동일하게 처리하면 된다.
삭제할 때의 명령어는 removeValue()이다.
let cardID = cardList[indexPath.row].id // (case1) ref.child("Item\(cardID)").removeValue() // (case2) ref.queryOrdered(byChild: "id").queryEqual(toValue: cardID).observe(.value) { [weak self] snapshot in guard let self = self, let value = snapshot.value as? [String: [String: Any]], let key = value.keys.first else { return } self.ref.child(key).removeValue() }
무엇보다 Database가 어떻게 저장되는지 파악하는 것이 우선이다.
어플을 준비하면서 Database도 찐하게 해봐야겠다.
'서버 > 2.(Firebase) Realtime Database' 카테고리의 다른 글
[4]_2_1. (Firebase) RealTime Database 데이터 받아오기 (0) 2022.07.27