이전에 Isar에 대한 기초적인 기사를 게시했습니다.
이번에는 더욱 자세한 Isar의 클래스 정의 및 데이터 조작 방법에 대해 소개합니다.
개발에 참고가 되길 바랍니다!
준비
Isar를 사용하려면 다음과 같은 준비가 필요합니다.
pubspec.yaml 설정
// 다음 패키지를 추가하세요.
dependencies:
isar:
isar_flutter_libs:
dev_dependencies:
build_runner:
isar_generator:
Isar 인스턴스 생성
import 'package:flutter/material.dart';
import 'package:isar/isar.dart';
import 'package:path_provider/path_provider.dart';
// Riverpod을 사용할 경우
import 'package:flutter_riverpod/flutter_riverpod.dart';
/// 직접 만든 Isar용 프로바이더의 저장 위치
import 'package:myApp/email_repository.dart';
// main 내에서 생성
Future<void> main() async {
// 로컬DB의 저장 위치 지정
final dir = await getApplicationSupportDirectory();
// Isar 인스턴스 생성
final isar = await Isar.open([EmailSchema], directory: dir.path);
// Isar 인스턴스 생성
runApp(ProviderScope(
overrides: [
emailIsarProvider.overrideWithValue(isar),
],
child: const MyApp(),
));
// 참고) 여러 컬렉션을 사용할 경우
Future<void> main() async {
// 로컬DB의 저장 위치 지정
final dir = await getApplicationSupportDirectory();
// Isar 인스턴스 생성
final isar = await Isar.open([UserSchema, EmailSchema], directory: dir.path);
// Isar 인스턴스 생성
runApp(ProviderScope(
overrides: [
userIsarProvider.overrideWithValue(isar),
emailIsarProvider.overrideWithValue(isar),
],
child: const MyApp(),
));
}
컬렉션 정의 방법
NoSQL에서는 컬렉션과 도큐먼트로 데이터가 관리됩니다.
관계형 데이터베이스와 비교하면 다음과 같은 관계입니다.
테이블 : 컬렉션
레코드 : 도큐먼트
Isar의 컬렉션을 정의하려면 데이터 구조를 클래스로 정의해야 합니다.
기본적인 컬렉션 정의
Isar에서 데이터 클래스를 정의하려면 @collection 애노테이션을 사용합니다.
다음은 Email이라는 이름의 컬렉션을 정의하는 예입니다.
@collection
class Email {
Email {
Id? id;
required title;
required updatedAt;
}
Id? id;
final String title;
@Index() // "@Index()"를 사용하면 그 아래 필드의 인덱스가 생성됩니다
final DateTime updatedAt;
}
이 클래스에는 id, title, updatedAt이라는 세 가지 필드가 있습니다.
id 필드는 데이터베이스 내에서 각 항목을 고유하게 식별하는 데 사용됩니다.
id는 Isar에서 자동으로 번호를 부여합니다.
IsarDB에 title과 updatedAt을 추가하면 id가 자동으로 부여됩니다.
실제로 저장되는 데이터 이미지:
{
"id": 1234, // 자동으로 부여된 id
"title": "How to use Isar!!"
"updatedAt": yyyy-mm-dd hh:mm
}
계층형 컬렉션 정의
경우에 따라 도큐먼트를 계층적 데이터 구조로 만들고 싶을 때가 있습니다.
이럴 때는 @embedded 애노테이션을 사용하여 자식 클래스를 정의합니다.
@collection
class Email {
Email {
Id? id;
required title;
required updatedAt;
required recipient;
}
Id? id;
final String title;
@Index()
final DateTime updatedAt;
final Recipient? recipient;
}
@embedded
class Recipient {
String? name;
String? address;
}
이 구조에서는 Email 클래스에 Recipient 클래스가 계층화되어 있습니다.
데이터 이미지:
{
"id": 99999,
"title": "How to use Isar!!",
"recipient": {
"name": "John Doe",
"address": "john.doe@gmail.com"
}
}
등록 업데이트 삭제 쿼리 작성
다음은 Isar를 사용한 CRUD 작업입니다.
단일 데이터 등록 및 업데이트
새 데이터를 데이터베이스에 추가하려면 컬렉션 정의에서 인스턴스를 생성하여 데이터베이스에 저장합니다.
“put“을 사용합니다.
같은 id의 데이터가 존재하면 업데이트, 존재하지 않으면 등록됩니다.
final Isar _isar; // 이후 생략
final email = Email()
..title = "How to use Isar CRUD!!"
..recipient = Recipient()
..name = "Jane Doe"
..address = "jane.doe@gmail.com";
await _isar.emails.put(email);
//emails는 생성 파일(이번 경우 email_dto.g.dart)에 정의된 컬렉션 클래스입니다.
여러 데이터 등록 및 업데이트
일반적으로 여러 데이터를 한 번에 처리하려면 writeTxn 메소드를 사용하여 트랜잭션 처리를 합니다.
여러 데이터를 등록 또는 업데이트하려면 “putAll“을 사용합니다.
await isar.writeTxn(() async {
await isar.emails.putAll([email1, email2]);
});
단일 데이터 삭제
데이터 삭제는 삭제할 데이터의 id를 지정합니다. “delete“를 사용합니다.
await isar.emails.delete(emailId);
여러 데이터 삭제
조건에 맞는 여러 데이터를 삭제하려면 “deleteAll“을 사용합니다.
await isar.emails.delete(emailId);
검색 쿼리 작성
다음은 데이터베이스 내의 데이터를 검색할 때 유용한 메소드입니다.
Where 절
특정 조건을 충족하는 데이터를 찾으려면 “where“을 사용합니다.
단, where를 사용할 수 있는 필드는 인덱스를 가진(@Index()가 붙은) 필드만 가능합니다.
where를 사용할 경우 아래와 같이 “where()”과 “findAll()” 사이에 조건을 넣습니다.
// updatedAt이 지정된 시간의 도큐먼트를 검색
final results = isar.emails
.where()
.updatedAtEqualTo("2024-12-31 23:59")
.findAll();
Where 절에서는 다음과 같은 조건을 사용할 수 있습니다.
쿼리 (필드 title의 경우) | 기능 |
---|---|
.titleEqualTo(“Title Name”) | “Title Name”과 동일한 값에 일치 |
.titleBetween(“T”, “Title Name”) | “T”(lower)와 “Title Name”(upper) 사이의 값에 일치 |
.titleGreaterThan(“Title Name”) | “Title Name”보다 큰 값에 일치 |
.titleLessThan(“Title Name”) | “Title Name”보다 작은 값에 일치. 기본값으로는 null 값을 포함 |
Filter 절 사용 방법
더 복잡한 조건을 설정하려면 “filter“를 사용합니다.
filter는 인덱스가 없는 필드에도 사용할 수 있지만 where보다 느립니다.
(아마 데이터를 가져온 후에 필터링하기 때문입니다.)
filter를 사용할 경우 아래와 같이 “filter()”와 “findAll()” 사이에 조건을 넣습니다.
// title이 "How"(문자의 대소문자 구분 없이)로 시작하는 도큐먼트를 검색
final filteredResults = isar.emails
.filter()
.titleStartsWith("How", caseSensitive: false)
.findAll();
쿼리 조건
위 외에도 다양한 조건으로 검색할 수 있습니다.
이들은 ~.g.dart 파일에 생성되어 있습니다.
쿼리 (필드 title의 경우) | 기능 |
---|---|
.titleEqualTo(“Title Name”) | “Title Name”과 동일한 값에 일치 |
.titleBetween(“T”, “Title Name”) | “T”(lower)와 “Title Name”(upper) 사이의 값에 일치 |
.titleGreaterThan(“Title Name”) | “Title Name”보다 큰 값에 일치 |
.titleLessThan(“Title Name”) | “Title Name”보다 작은 값에 일치. 기본값으로는 null 값을 포함 |
.titleIsNull() | null 인 항목 |
.titleIsNotNull() | null이 아닌 항목 |
.titleLengthGreaterThan(5) | 값의 길이가 5보다 큰 값에 일치 |
And Or 등의 논리 연산자
And와 Or을 사용하여 여러 조건을 지정할 수 있습니다.
// title이 "How"로 시작하고, updatedAt이 지정된 시간의 도큐먼트를 검색
final filteredResults = isar.emails
.filter()
.titleStartsWith("How")
.and()
.updatedAtEqualTo("2024-12-31 23:59")
.findAll();
그 외에도 SQL에서 자주 사용하는 연산자를 사용할 수 있습니다.
쿼리 (필드 title의 경우) | 기능 |
---|---|
.and() | and (앞과 뒤가 True인 경우, True) |
.or() | or (앞과 뒤 중 하나가 True인 경우, True) |
.xor() | xor (앞과 뒤 중 하나만 True인 경우, True) |
.not() | not (뒤 조건의 결과를 반전) |
.group() | group (조건을 그룹화) |
Where 절과 Filter 절의 조합
일반적으로 Where와 Filter를 조합한 쿼리를 작성합니다.
// title이 "How"보다 크고, updatedAt이 Null이 아닌 도큐먼트를 검색
final filteredResults = isar.emails
.titleGreaterThan("How")
.filter()
.updatedAtIsNotNull()
.findAll();
Where가 더 빠르기 때문에, 가능한 한 Where로 대상을 좁히고, Filter로 복잡한 조건을 지정합니다.
Offset과 Limit
데이터의 내용이 아닌 개수로 결과의 일부를 얻으려면 “offset“과 “limit“을 설정합니다.
offset은 처음부터 얻지 않을 개수, limit은 얻을 개수입니다.
final paginatedResults = isar.emails
.where()
.findAll(offset: 10, limit: 5); // 11번째부터 5개를 가져옴
전체 검색
데이터베이스 내의 모든 데이터를 얻으려면 “findAll“만 사용합니다.
final allEmails = await isar.emails
.findAll();
마지막으로
Flutter와 Isar를 사용하여 데이터를 효율적으로 관리하는 기본적인 방법을 설명했습니다.
아직도 편리한 기능이 많이 있습니다. 이번에 소개하지 못한 기능은 추후에 기사를 작성하겠습니다.
공식 사이트에도 사용 방법이 기재되어 있으니 참고하세요!
https://isar.dev/ko/crud.html