以前、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という3つのフィールドがあります。
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とFillterを組み合わせたクエリを作成します。
// titleが"How"より大きく、updatedAtがNullではないドキュメントの検索
final filteredResults = isar.emails
.titleGreaterThan("How")
.filter()
.updatedAtIsNotNull()
.findAll();
Whereの方が高速のため、極力Whereで対象を絞り、Fillterで複雑な条件を指定します。
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/ja/crud.html