본문 바로가기

기타/Firebase

Firebase 자식 노드 제거 및 참조하기

안드로이드 스튜디오에서 기억해둘 것이 있어서 정리해둔다.

 

모든 Firebase 세팅이 끝나고 FirebaseManageEngine.class를 다음과 같이 작성한다.

 

public class FirebaseManageEngine {
    static private FirebaseDatabase LocalDB = FirebaseDatabase.getInstance();
    static private DatabaseReference LocalDBref = FirebaseDatabase.getInstance().getReference();

    public FirebaseManageEngine(){
    }

    public static void RenewDatabaseReference(){
        LocalDBref = FirebaseDatabase.getInstance().getReference();
    }

    public static void RenewDatabase(){
        LocalDB = FirebaseDatabase.getInstance();
    }


    //getter & setter
    public static DatabaseReference getFreshLocalDBref(){
        RenewDatabaseReference();
        return LocalDBref;
    }

    public static FirebaseDatabase getFreshLocalDB(){
        RenewDatabase();
        return LocalDB;
    }
}

LocalDBref는 최상위 루트 Layer의 reference를 뜻함.

 

예를 들어 위와 같은 노드 체계를 갖춘 DB에서 transactions 중 특정 조건(timestamp의 date 값이 어떠한 값보다 적은)을 만족하는 노드들을 모두 삭제하려고 할 때, 다음과 같은 방식을 사용하면 된다.

(불행하게도 모두 지워서 transaction이 하나밖에 없다.. 여러 개 있다고 가정하자.)

 

위의 과정이 어떤 버튼의 클릭 시 실행되게 하려면 그냥 아래의 코드를 onClickListener()에 넣어버리면 된다.

 

String stamp = "190...(생략)";
try {
    final long standTamp = Global.transactionDateFormat.parse(stamp).getTime();

    final DatabaseReference myref = FirebaseManageEngine.getFreshLocalDB().getReference(Global.rootName+"/transactions");
    myref.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
            for(DataSnapshot data : dataSnapshot.getChildren()){
                String str = data.child("timestamp").getValue().toString();
                try {
                    long time = Global.transactionDateFormat.parse(str).getTime();
                    if(time <= standTamp) {
                        myref.child(data.getKey()).removeValue();
                        new LogEngine().sendLog("remove this");
                    }
                }catch(ParseException e){
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {

        }
    });
}catch(ParseException e){
    e.printStackTrace();
}

DataSnapShot의 dataEntry를 추출하여 나온 data 하나하나는 object 취급되어 getValue(SampleClass.class);

 

이런 식으로 받아올 수 있긴 한데(Mapping이 필요함), 나는 변환이 잘 안되는 것 같다.

 

for 문 내의 data가 각 transaction 항목들을 가지고 있다. (toString으로 출력하면 JSON 형식으로 출력됨)

 

해당 data들은 child() 함수로 element들을 JSON처럼 파고들 수 있는데, 들어가서 getValue() 호출 시 원하는 값을 얻어올 수 있다.

 

String str = data.child("timestamp").getValue().toString();

이와 같이 getKey()를 통해 키를 얻고 reference 재정의할 필요 없이 바로 접근할 수 있다는 것이다.

 

해당 데이터들이 RecyclerView 같은 list 형식에 속해 있다면,

DatabaseReference myref = FirebaseManageEngine.getFreshLocalDB().getReference(Global.rootName+"/transactions");
myref.addChildEventListener(new ChildEventListener() {
    @Override
    public void onChildAdded(@NonNull DataSnapshot snapshot, @Nullable String s) {
        //do something..
    }

    @Override
    public void onChildChanged(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {

    }

    @Override
    public void onChildRemoved(@NonNull DataSnapshot dataSnapshot) {
        String stamp = dataSnapshot.getValue(MoneyTransaction.class).timestamp;
        Iterator<MoneyTransaction> iter = transactions.iterator();
        while(iter.hasNext()){
            MoneyTransaction trans = iter.next();
            if(trans.timestamp.equals(stamp))
                iter.remove();
        }
        mAdapter.notifyDataSetChanged();

    }

    @Override
    public void onChildMoved(@NonNull DataSnapshot dataSnapshot, @Nullable String s) {

    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {

    }
});

위와 같은 형식으로 해당 리스트에 iterator를 적용하여 remove를 실행해준다.

 

iterator 없이 일반 loop를 돌린다면 ConcurrentModificationException이 발생할 것이다.