Hi I am new to Isar Flutter. I want to know is there any way to import existing JSON file into Isar?
I try to search this on the Internet but can't find much on it.
Below is the structure of my Json file.
{
"food": [
{
"id": "0001",
"name": "Cake",
"description": [
{
"type": "Chocolate",
"quantity": 1
},
{
"type": "fruits",
"quantity": 3
},
{
"type": "Corn",
"quantity": 6
}
]
},
{
"id": "0002",
"name": "Raised",
"description": [
{
"type": "Grape",
"quantity": 6
},
{
"type": "Wheat",
"quantity": 2
}
]
}
],
"instruction": [
{
"category": "instruction_1002",
"content": "abc1234"
},
{
"category": "instruction_1003",
"content": "def56789"
}
]
}
First, let's set the above existing json data to a constants.dart
const response = {
"food": [
{
"id": "0001",
"name": "Cake",
"description": [
{"id": "instruction_1002", "type": "Chocolate"},
{"id": "instruction_1003", "type": "fruits"},
{"id": "instruction_1004", "type": "Corn"}
]
},
{
"id": "0002",
"name": "Raised",
"description": [
{"id": "instruction_2002", "type": "Grape"},
{"id": "instruction_2003", "type": "Wheat"}
]
}
],
"instruction": [
{"category": "instruction_1002", "content": "abc1234"},
{"category": "instruction_1003", "content": "def56789"}
]
};
From this data we'll get to create 3 collections and one of them will be an embedded object
Create a folder called collections.
Inside the collections folder create a dart file called food.dart
This file will contain a collection called Food and another collection called Description that will be embedded to the Food collection. The properties are also defined by the keys provided in the existing json data in constants.dart
import 'package:isar/isar.dart';
part 'food.g.dart';
@Collection()
class Food {
Food({this.foodId, this.name, this.description});
Id? foodId = Isar.autoIncrement;
String? id;
String? name;
List<Description>? description;
}
@embedded
class Description {
Description({this.id, this.type});
String? id;
String? type;
}
Inside the collections folder create another dart file called instruction.dart
import 'package:isar/isar.dart';
part 'instruction.g.dart';
@Collection()
class Instruction {
Instruction({this.category, this.content});
Id? id = Isar.autoIncrement;
String? category;
String? content;
}
Next, we need to create generated files for these two files by using build_runner.
Import the build_runner flutter package.
Run the command below to generate the files:
flutter pub run build_runner build
You'll find 2 files created in the collections folder: food.g.dart & instruction.g.dart
Next, we'll go to the necessary class, to import the existing json data to isar database. In my case I'll use the skeleton below to proceed.
import 'package:flutter/material.dart';
void main() async {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
final Isar isar;
const MyApp({super(key: key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text("Isar Database"),
),
body: Center(
child: TextButton(
onPressed: () {
//IMPORT LOGIC HERE
},
child: const Text("Import JSON"),
),
),
));
}
}
Now let's add the import json logic.
Ensure you have these packages installed.
isar: ^3.0.5
isar_generator: ^3.0.5
isar_flutter_libs: ^3.0.5
path_provider: ^2.0.13
Let's initialize isar to the application in the main function. It will look like this:
import 'package:flutter/material.dart';
import 'package:import_to_isar/collections/food.dart';
import 'package:import_to_isar/collections/instruction.dart';
import 'package:import_to_isar/constant.dart';
import 'package:isar/isar.dart';
import 'package:path_provider/path_provider.dart';
void main() async {
//INITIALIZE ISAR TO THE APPLICATION
WidgetsFlutterBinding.ensureInitialized();
final dir = await getApplicationSupportDirectory();
if (dir.existsSync()) {
final isar = await Isar.open([FoodSchema, InstructionSchema]);
runApp(MyApp(isar: isar));
}
}
class MyApp extends StatelessWidget {
final Isar isar;
const MyApp({Key? key, required this.isar}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text("Isar Database"),
),
body: Center(
child: TextButton(
onPressed: () {
//IMPORT LOGIC HERE
},
child: const Text("Import JSON"),
),
),
));
}
}
Now, we create a function that will use the importJson() method by Isar database as shown below.
importjson() async {
//We first clear the database - not a must!
await isar.writeTxn(() async {
await isar.clear();
});
importFood(); //This function imports the data in the key 'food' from the existing json data
importInstructions(); //This function imports the data in the key 'instruction' from the existing json data
}
importFood() async {
await isar.writeTxn(() async {
await isar.foods.importJson(response['food']!);
});
}
importInstructions() async {
await isar.writeTxn(() async {
await isar.instructions.importJson(response['instruction']!);
});
}
Full code:
import 'package:flutter/material.dart';
import 'package:import_to_isar/collections/food.dart';
import 'package:import_to_isar/collections/instruction.dart';
import 'package:import_to_isar/constant.dart';
import 'package:isar/isar.dart';
import 'package:path_provider/path_provider.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final dir = await getApplicationSupportDirectory();
if (dir.existsSync()) {
final isar = await Isar.open([FoodSchema, InstructionSchema]);
runApp(MyApp(isar: isar));
}
}
class MyApp extends StatelessWidget {
final Isar isar;
const MyApp({Key? key, required this.isar}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text("Isar Database"),
),
body: Center(
child: TextButton(
onPressed: () {
importjson();
},
child: const Text("Import JSON"),
),
),
));
}
importjson() async {
await isar.writeTxn(() async {
await isar.clear();
});
importFood();
importInstructions();
}
importFood() async {
await isar.writeTxn(() async {
await isar.foods.importJson(response['food']!);
});
}
importInstructions() async {
await isar.writeTxn(() async {
await isar.instructions.importJson(response['instruction']!);
});
}
}
The UI looks like this:
To view the data in the Isar database, use the Isar Inspector. You'll find the link on the terminal of your IDE when you run the application.
This is how my Isar Inspector looks like:
To display the information stored in the 2 collections respectively, let's:
class MyApp extends StatefulWidget {
final Isar isar;
const MyApp({Key? key, required this.isar}) : super(key: key);
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text("Isar Database"),
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Align(
alignment: Alignment.center,
child: OutlinedButton(
onPressed: () {
importjson();
},
child: const Text("Import JSON"),
),
),
],
),
),
));
}
importjson() async {
await widget.isar.writeTxn(() async {
await widget.isar.clear();
});
importFood();
importInstructions();
}
importFood() async {
await widget.isar.writeTxn(() async {
await widget.isar.foods.importJson(response['food']!);
});
}
importInstructions() async {
await widget.isar.writeTxn(() async {
await widget.isar.instructions.importJson(response['instruction']!);
});
}
}
Future<List<Food>> exportjson() async {
return await widget.isar.foods.where().findAll();
}
const Text(
"Exported JSON",
style: TextStyle(fontWeight: FontWeight.bold),
),
FutureBuilder<List<Food>>(
future: exportjson(),
builder: (context, snapshot) {
List<Food> foodlist = snapshot.data ?? [];
if (foodlist.isNotEmpty) {
return Column(
children: [],
);
} else {
return const SizedBox.shrink();
}
})
List<Widget> buildWidget(List<Food> f) {
List<Widget> x = [];
for (int i = 0; i < f.length; i++) {
x.add(SizedBox(
width: MediaQuery.of(context).size.width * 0.8,
child: Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child:
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(f[i].name ?? ""),
const Text(
"Description",
style: TextStyle(fontSize: 11, fontWeight: FontWeight.bold),
),
]),
),
),
));
}
return x;
}
FutureBuilder<List<Food>>(
future: exportjson(),
builder: (context, snapshot) {
List<Food> foodlist = snapshot.data ?? [];
if (foodlist.isNotEmpty) {
return Column(
children: buildWidget(foodlist),
);
} else {
return const SizedBox.shrink();
}
})
The display will look like this:
Future<List<Widget>> buildDescription(List<Description> d) async {
List<Widget> y = [];
for (int i = 0; i < d.length; i++) {
Instruction? x = await widget.isar.instructions
.where()
.filter()
.categoryEqualTo(d[i].id)
.findFirst();
String content = x?.content ?? "";
y.add(ListTile(
leading: Text(
d[i].type!,
style: const TextStyle(fontWeight: FontWeight.bold),
),
trailing: Text(content),
));
}
return y;
}
List<Widget> buildWidget(List<Food> f) {
List<Widget> x = [];
for (int i = 0; i < f.length; i++) {
List<Description> description = f[i].description ?? [];
x.add(SizedBox(
width: MediaQuery.of(context).size.width * 0.8,
child: Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child:
Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text(f[i].name ?? ""),
const Text(
"Description",
style: TextStyle(fontSize: 11, fontWeight: FontWeight.bold),
),
FutureBuilder(
future: buildDescription(description),
builder: (context, snapshot) {
List<Widget> c = snapshot.data ?? [];
return Column(children: c);
})
]),
),
),
));
}
return x;
}
Now the screen will look as shown displaying description information of each food.