Previously, I posted a basic article about Isar.
This time, I will introduce more detailed Isar class definitions and data manipulation methods.
I hope it will be helpful for your development!
Preparation
When using Isar, the following preparations are necessary.
Setting up pubspec.yaml
// Add the following packages.
dependencies:
isar:
isar_flutter_libs:
dev_dependencies:
build_runner:
isar_generator:
Creating an Isar Instance
import 'package:flutter/material.dart';
import 'package:isar/isar.dart';
import 'package:path_provider/path_provider.dart';
// When using Riverpod
import 'package:flutter_riverpod/flutter_riverpod.dart';
/// Location for storing custom Isar providers
import 'package:myApp/email_repository.dart';
// Create within main
Future<void> main() async {
// Specify the location to save the local DB
final dir = await getApplicationSupportDirectory();
// Create an Isar instance
final isar = await Isar.open([EmailSchema], directory: dir.path);
// Create an Isar instance
runApp(ProviderScope(
overrides: [
emailIsarProvider.overrideWithValue(isar),
],
child: const MyApp(),
));
// For reference, if using multiple collections
Future<void> main() async {
// Specify the location to save the local DB
final dir = await getApplicationSupportDirectory();
// Create an Isar instance
final isar = await Isar.open([UserSchema, EmailSchema], directory: dir.path);
// Create an Isar instance
runApp(ProviderScope(
overrides: [
userIsarProvider.overrideWithValue(isar),
emailIsarProvider.overrideWithValue(isar),
],
child: const MyApp(),
));
}
Defining Collections
In NoSQL, data is managed in collections and documents.
In relational databases, the relationship is as follows:
Table: Collection
Record: Document
To define a collection in Isar, you need to define the data structure as a class.
Basic Collection Definition
In Isar, data classes are defined using the @collection annotation.
Here is an example of defining a collection named Email.
@collection
class Email {
Email {
Id? id;
required title;
required updatedAt;
}
Id? id;
final String title;
@Index() // "@Index()" creates an index for the field below it
final DateTime updatedAt;
}
This class has three fields: id, title, and updatedAt.
The id field is used to uniquely identify each entry in the database.
The id is automatically assigned by Isar.
When adding title and updatedAt to the IsarDB, the id is automatically assigned.
Data storage image:
{
"id": 1234, // Automatically assigned id
"title": "How to use Isar!!"
"updatedAt": yyyy-mm-dd hh:mm
}
Defining Hierarchical Collections
Sometimes you may want to structure documents in a hierarchical manner.
In such cases, define the child class using the @embedded annotation.
@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;
}
In this structure, the Recipient class is nested within the Email class.
Data image:
{
"id": 99999,
"title": "How to use Isar!!",
"recipient": {
"name": "John Doe",
"address": "john.doe@gmail.com"
}
}
Writing Queries for Registration, Update, and Deletion
Next, let’s look at CRUD operations using Isar.
Single Data Registration/Update
To add new data to the database, create an instance from the collection definition and save it to the database using “put“.
If data with the same id exists, it will be updated; if it does not exist, it will be registered.
final Isar _isar; // Omitted below
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" is the collection class defined in the generated file (in this case, email_dto.g.dart)
Batch Data Registration/Update
When dealing with multiple data at once, use the writeTxn method for transaction processing.
To register or update multiple data, use “putAll“.
await isar.writeTxn(() async {
await isar.emails.putAll([email1, email2]);
});
Single Data Deletion
To delete data, specify the id of the data to be deleted using “delete“.
await isar.emails.delete(emailId);
Batch Data Deletion
To delete multiple data that match certain conditions, use “deleteAll“.
await isar.emails.deleteAll(emailIds);
Writing Search Queries
Next, let’s look at useful methods for searching data within the database.
Where Clause
To find data that meets specific conditions, use “where“.
However, the fields that can use where must have an index (with @Index()).
When using where, conditions are placed between “where()” and “findAll()”.
// Search for documents where updatedAt matches the specified time
final results = isar.emails
.where()
.updatedAtEqualTo("2024-12-31 23:59")
.findAll();
The following conditions can be used in the where clause.
Query (for the title field) | Function |
---|---|
.titleEqualTo(“Title Name”) | Matches values equal to “Title Name” |
.titleBetween(“T”, “Title Name”) | Matches values between “T” (lower) and “Title Name” (upper) |
.titleGreaterThan(“Title Name”) | Matches values greater than “Title Name” |
.titleLessThan(“Title Name”) | Matches values less than “Title Name”. By default, includes null values. |
Using Filter Clauses
To set more complex conditions, use “filter“.
Filters can be used on fields without an index, but they are slower than where.
(Probably because the data is retrieved first and then filtered.)
When using filter, conditions are placed between “filter()” and “findAll()”.
// Search for documents where the title starts with "How" (case insensitive)
final filteredResults = isar.emails
.filter()
.titleStartsWith("How", caseSensitive: false)
.findAll();
Filter Conditions
Besides the above, various conditions can be used.
These are created in the ~.g.dart.
Query (for the title field) | Function |
---|---|
.titleEqualTo(“Title Name”) | Matches values equal to “Title Name” |
.titleBetween(“T”, “Title Name”) | Matches values between “T” (lower) and “Title Name” (upper) |
.titleGreaterThan(“Title Name”) | Matches values greater than “Title Name” |
.titleLessThan(“Title Name”) | Matches values less than “Title Name”. By default, includes null values. |
.titleIsNull() | Matches null values |
.titleIsNotNull() | Matches non-null values |
.titleLengthGreaterThan(5) | Matches values with a length greater than 5 |
Logical Operators such as And and Or
Use And and Or to specify multiple conditions.
// Search for documents where the title starts with "How" and updatedAt matches the specified time
final filteredResults = isar.emails
.filter()
.titleStartsWith("How")
.and()
.updatedAtEqualTo("2024-12-31 23:59")
.findAll();
Other operators commonly used in SQL can also be used.
Query (for the title field) | Function |
---|---|
.and() | and (True if both are True) |
.or() | or (True if either is True) |
.xor() | xor (True if only one is True) |
.not() | not (Inverts the result of the following condition) |
.group () | group (Groups conditions) |
Combining Where and Filter Clauses
Typically, queries are created by combining Where and Filter clauses.
// Search for documents where the title is greater than "How" and updatedAt is not null
final filteredResults = isar.emails
.titleGreaterThan("How")
.filter()
.updatedAtIsNotNull()
.findAll();
Since Where is faster, try to narrow down the target as much as possible with Where and then specify complex conditions with Filter.
Offset and Limit
To get a subset of results by the number of records rather than the content, set “offset” and “limit“.
Offset specifies the number of records not to retrieve from the start, and limit specifies the number of records to retrieve.
final paginatedResults = isar.emails
.where()
.findAll(offset: 10, limit: 5); // Retrieve 5 records starting from the 11th
Search Entire Database
To retrieve all data in the database, use “findAll” alone.
final allEmails = await isar.emails
.findAll();
Conclusion
I have explained the basic methods for efficiently managing data using Flutter and Isar.
There are still many useful features. I will write articles about the features that I could not introduce this time in the future.
There are also usage instructions on the official website, so please refer to them as well!!
https://isar.dev/crud.html