Isarのデータ操作(クラス定義、CRUD操作)

以前、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"
  }
}

クラス定義後はbuild_runnerを実行し、~.g.dartを作成する必要があります。
以下コマンドをターミナルで実行してください。

// キャッシュのクリーン
flutter pub run build_runner clean
// コード生成実行
flutter pub run build_runner build --delete-conflicting-outputs

登録更新削除クエリの記述

次に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句では以下の条件が使用できます。

Filter句の使い方

より複雑な条件を設定するには、”filter“を使います。
filterはインデックスがないフィールドにも使用できますが、whereより低速です。
(恐らくデータを取得してから絞っているため)

filterを使う場合は以下の様に、”filter()”と”findAll()”の間に条件を入れます。

// titleが"How"(文字の大小区別なし)から始まるドキュメントの検索
final filteredResults = isar.emails
    .filter()
    .titleStartsWith("How", caseSensitive: false)
    .findAll();

クリエ条件

上記以外にも、様々な条件で検索することができます。
これらは~.g.dartの中に作成されています。

And Or などの論理演算子

AndやOrを使って複数条件を指定することができます。

// titleが"How"から始まり、updatedAtが指定時間のドキュメントの検索
final filteredResults = isar.emails
    .filter()
    .titleStartsWith("How")
    .and()
    .updatedAtEqualTo("2024-12-31 23:59")
    .findAll();

その他にもSQLでよく使う演算子が使えます。

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

タイトルとURLをコピーしました