ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [LokiJS] 나의 삽질 후기
    programing/Language 2020. 5. 21. 23:06

    안녕하세요, Einere입니다.

    (광고 차단 기능을 꺼주시면 감사하겠습니다.)


    LokiJS

    개인 토이 프로젝트를 진행하다가 데이터를 저장해야 해야 할 필요가 생겼습니다. 그런데 저는 따로 서버를 구현하고 싶지 않았습니다. (AWS 프리티어도 만료되었슴..) 그래서 client-side in-memory DB를 라이브러리를 찾다가, LokiJS라는 라이브러리를 찾게 되었습니다.

    LokiJS is a document oriented database written in javascript, published under MIT License. Its purpose is to store javascript objects as documents in a nosql fashion and retrieve them with a similar mechanism. Runs in node (including cordova/phonegap and node-webkit), nativescript and the browser.

    뭐 대충 보자면 mongo DB와 비슷하게, 도큐먼트 기반 DB라고 합니다. 여러가지 잡다한 기능이 있지만, 사실 그렇게 큰 기능을 바라지는 않았습니다. 할 일 정보만 잘 저장하고 불러오면 충분했기 때문이죠.

     

    왜 안돼지..??

    프로젝트에 LokiJS를 설치하고 할 일에 대한 CRUD기능을 구현하면서 DB를 이용하는 코드도 작성했습니다.

    const updateTodoItem = useCallback((newTodoItem: Todo.TodoInfoTypeForUpdate) => {
        const copiedTodoInfos = deepCopy<Todo.TodoInfoType[]>(todoInfos);
        const indexForUpdate = copiedTodoInfos.findIndex((todoInfo) => todoInfo.id === newTodoItem.id);
    
        const todoItemForUpdate = makeTodoInfo(newTodoItem);
        copiedTodoInfos[indexForUpdate] = todoItemForUpdate;
        setTodoInfos(copiedTodoInfos);
    
        todoDB.findAndUpdate({
            'id': {
                '$eq': newTodoItem.id
            }
        }, (data) => {
            return {
                ...data,
                ...todoItemForUpdate
            };
        });
    
        db.saveDatabase();
    }, [todoInfos, db, todoDB]);
    

    코드 윗 부분은 리액트 컴포넌트의 상태를 갱신하는 코드이며, 아래 부분이 LokiJS를 이용해서 특정 도큐먼트를 갱신하는 코드입니다.

    이후, 로컬에서 테스트를 해보니 도큐먼트가 전혀 갱신되지 않았습니다. 😳

     

    공식 문서를 찾아보자

    혹시나 싶어 공식 문서를 찾아봤습니다.

     

    친절하면서도 불친절한 공식문서

    음.. 첫번째 인자는 object맞고, 두번째 인자도 function으로 맞는데.. 뭐가 잘못된거지?

     

    수 많은 삽질

    혹시라도 find()가 제대로 작동하지 않는가 싶어, console.log()를 이용해서 찍어 봤습니다.

    갱신해야 할, 할 일 정보가 잘 찍힌다

    음.. 제대로 잘 찾는 것 같습니다. 그런데 왜 DB 갱신이 안되는지 아직도 이해를 하지 못했습니다.

    공식 문서를 더 봐도 딱히 도움이 되는 게 없어서 코드를 직접 보기로 했습니다.

     

    우선 현재 filterObject는 함수가 아니라 객체이므로, else문이 실행되겠군요.

    다시 한번 find()가 잘 작동하는지 체크해봅니다.

     

    다시 확인해도 갱신해야 할, 할 일 정보가 잘 찍힌다

    로그가 좀 길긴 하지만, 변경전의 데이터입니다.

    그럼 이제 update()가 잘 작동하는지 체크해봅니다.

     

    확인 결과, 하단의 console.log()가 있는 부분이 실행 흐름이었습니다.

    한번 로그를 볼까요?

     

    전후가 똑같은 객체~

    놀랍게도 완전하게 동일합니다. titlefoo1로, content를 bar1로 변경했지만 전혀 의도대로 동작하지 않습니다.

    그런데 불현듯 무언가가 제 머리를 스치는 느낌이 들었습니다.

    다시 한번 코드를 자세히 보니..

     

    Mutable!

    updateFunction의 반환값을 전혀 사용하지 않고 있으며, rcd[this.filteredrows[idx]]를 그대로 update()의 인자로 넘겨주고 있습니다...😳

    리액트를 하느라 immutable에 익숙해진 저로써는 정말 경악을 금치 못할 코드입니다..

    "에이 저게 뭐 그리 대수인가?" 싶을 수 있지만, 진짜 대수입니다.

     

    todoDB.findAndUpdate({
        'id': {
            '$eq': newTodoItem.id
        }
    }, (data) => {
        data = {
            ...data,
            ...todoItemForUpdate
        };
    });
    

    updateFunction의 매개변수인 data에 새로운 객체를 할당했습니다. 이 경우, 바깥의 rcd[this.filteredrows[idx]]는 전혀 영향을 받지 않습니다. 따라서 data에 새로운 값을 할당하지 않으면서 갱신해야 됩니다.

     

    todoDB.findAndUpdate({
        'id': {
            '$eq': newTodoItem.id
        }
    }, (data) => {
        data.title = todoItemForUpdate.title;
        data.content = todoItemForUpdate.content;
        data.dueTime = todoItemForUpdate.dueTime;
    });
    

    제 경우는 단순히 속성 3개만 갱신하면 되지만, 만약 갱신이 필요한 속성이 수십, 수백개라면 어떨까요? 생각만 해도 끔찍합니다.. 😱

     

    공식 홈페이지의 코드

    심지어 더 골때리는건, 비슷한 역할을 하는 다른 함수에는 정상적으로 반환값을 사용하고 있습니다... 😡

     

    후기

    당연하게 콜백 함수의 반환값을 사용하겠지..라는 안일한 생각때문에 꽤나 고생했습니다만, 그래도 라이브러리를 왜 이렇게 만들었는지 이해하기는 좀 어렵습니다. (심지어 일관성도 없음..)

    적어도 공식 문서에 예시 코드라도 나와 있었다면 이렇게 헤메지는 않았을텐데 말이죠..

     

    그래서 LokiJS 저장소에 이슈를 올렸습니다.

    그런데 메인테인이 안된지 꽤 되어 보여서, 반응이 올지 안올지 모르겠네요.

    댓글

Designed by black7375.