필요 지식
javascript, IndexedDB, Dexie
SSR(Server Side Rendering) 방식으로 개발할때는 화면에 필요한 데이터를 거의 항상 서버로 부터 조회하게 됩니다. 그러나 CSR(Client Side Rendering) 방식으로 만들거나, 혹은 SPA(Single Page Application) 로 구현된 웹페이지에서는 데이터를 항상 서버에서 조회하지 않고 로컬 브라우저에 저장하고 재사용하는 방법을 고민하게 됩니다.
브라우저에서는 Session Storage
, Local Storage
, IndexedDB
를 활용하여 데이터를 저장할수 있습니다. Session Storage, Local Storage 가 사용하기엔 쉽지만 데이터양이 많고 구조화가 필요한 경우엔 IndexedDB
를 사용해야 합니다. 하지만 기본적인 기능만 사용할려고 해도 굉장히 지저분한 코딩을 해야 한다는 것을 곧 깨닫게 됩니다.
IndexedDB 참고
https://developer.mozilla.org/ko/docs/IndexedDB/Using_IndexedDB
이때 사용 가능한 매우 훌륭한 Wrapper 라이브러리가 있습니다. 바로 Dexie
입니다. Dexie 는 IndexedDB를 간결하게 사용할수 있도록 도와줍니다.
경로 : https://dexie.org
설치 : npm install dexie, yarn add dexie
현재버전 : 2.0.4
특징
가장 큰 특징 두가지는 기존에 사용하던 IndexedDB 를 마이그레이션 할 필요없이 사용 가능하다는 것과, Promise/A+ 와 ECMA6을 지원한다는 것입니다. 그리고 npm 이나 yarn을 사용하지 않더라도 CDN 으로 제공하는 스크립트를 추가하는 것만으로 간단하게 적용이 가능합니다.
상세한 비교 설명은 아래 URL을 참고하시면 되겠습니다.
about Dexie.js
https://dexie.org/docs/Dexie.jsdexie vs lawnchair vs localforage vs pouchdb
https://www.npmtrends.com/dexie-vs-lawnchair-vs-localforage-vs-pouchdb
DB 생성
var db = new Dexie("MyDatabase");
db.version(1).stores({
friends: "++id, name, age, *tags",
gameSessions: "id, score"
});
store()
함수를 통해 사용할 테이블의 구조를 정의하면 됩니다. 테이블의 컬럼에 정의 가능한 속성은 아래와 같습니다.
기호 | 의미 |
---|---|
++ | Auto-incremented primary key |
& | Unique |
* | Multi-entry index |
[A+B] | Compound index |
DB 업그레이드
만약 서비스를 제공중에 DB 구조를 바꿔야 할 경우, 서버 DB에서도 마이그레이션 작업이 필요하듯이 IndexedDB도 마이그레이션이 필요합니다. 아래 소스는 변경되는 구조를 버전2로 정의하고 upgrade()
에서 마이그레이션 작업을 정의하고 있습니다.
db.version(1).stores({
friends: "++id,name,age,*tags",
gameSessions: "id,score"
});
db.version(2).stores({
friends: "++id, [firstName+lastName], yearOfBirth, *tags", // Change indexes
gameSessions: null // Delete table
}).upgrade(tx => {
// Will only be executed if a version below 2 was installed.
return tx.friends.modify(friend => {
friend.firstName = friend.name.split(' ')[0];
friend.lastName = friend.name.split(' ')[1];
friend.yearOfBirth = new Date(new Date().getFullYear() - friend.age, 0);
delete friend.name;
delete friend.age;
});
});
데이터 추가
단일 데이터를 추가할수도 있고, 여러개의 데이터를 대량으로 추가할수도 있습니다.Dexie
에서 제공하는 CRUD 함수들은 Promise
로 제공하기 때문에 다른 Promise 로직과 결합하여 흐름제어가 가능합니다. 다른 Promise와 결합할 필요가 없다면 await
키워드를 사용하여 호출을 완료할 수 있습니다.
await db.friends.add({name: "Josephine", age: 21});
await db.friends.bulkAdd([
{name: "Foo", age: 31},
{name: "Bar", age: 32}
]);
데이터 수정
데이터 update 를 위해 Table.put()
, Table.bulkPut()
, Table.update()
, Collection.modify()
를 사용할 수 있습니다. 여기서 put은 같은 키의 값이 존재할때는 update, 존재하지 않을때는 insert를 하는 upsert 의미로 동작하므로 매우 유용합니다.
데이터 조회
데이터를 조회할때는 where()
와 get()
을 사용할수 있습니다. 단일건을 조회할때는 get()
이 좀더 간단한 방법을 제공하고 있습니다.
const forbundsKansler = await db.friends.where({
firstName: "Angela",
lastName: "Merkel"
}).first();
const forbundsKansler = await db.friends.get({
firstName: "Angela",
lastName: "Merkel"
});
그러나 복잡한 조건을 적용하기 위해서는 where()
를 사용해야 합니다. 메소드 체인으로 조건식을 적용할 수 있습니다.
const someFriends = await db.friends
.where("age").between(20, 25)
.offset(150).limit(25)
.toArray();
await db.friends
.where("name").equalsIgnoreCase("josephine")
.each(friend => {
console.log("Found Josephine", friend);
});
const abcFriends = await db.friends
.where("name")
.startsWithAnyOfIgnoreCase(["a", "b", "c"])
.toArray();
// This query is equal to:
// select * from friends where firstName='Angela' order by lastName
const angelasSortedByLastName = await db.friends
.where('[firstName+lastName]')
.between([["Angela", ""], ["Angela", "\uffff"])
.toArray()
const best5GameSession = await db.gameSessions
.orderBy("score").reverse()
.limit(5)
.toArray();
'javascript' 카테고리의 다른 글
[javascript] 숫자를 한글로 변환하는 함수 (2) | 2019.09.03 |
---|---|
[javascript] callback, Promise, async/await 모두 지원하는 함수 만들기 (0) | 2019.08.28 |
[javascript] 플러그인 없는 Text-To-Speech 만들기 (1) | 2019.08.20 |
[javascript] moment.js 사용하기 (0) | 2019.05.21 |
[javascript] scope와 호이스팅(hoisting) (0) | 2019.05.08 |