UnQLite database plugin wrapped for flutter.UnQLite is an embedded NoSql database, see here for details.
Todo:
- key-value store
- JSON document store
Add dependencies:
unqlite: latest
unqlite_flutter: latest
Simple key-value store:
// create or open a database
UnQLite db = UnQLite.open("${appDocDir.path}/test.db");
// save key-value pairs
db.store("name", "Alex");
db.store("age", 18);
db.store(19, "haha");
// get value by key
// but you have to specify the generic type of the value
debugPrint(db.fetch<String>("name"));
debugPrint('${db.fetch<int>("age")}');
debugPrint(db.fetch<String>(19));
// another way to get a value
db.fetchCallback<int>("age", (val) {
debugPrint('age=$val');
});
Of course, there is another way to get the data, it might be faster than fetch
:
var cursor = db.cursor();
cursor.seek('name');
debugPrint('=> ${cursor.key} => ${cursor.value}');
Also you can use transactions which is a great feature:
var trans = db.transaction().begin();
try {
for (var i = 0; i < 100000; i++) {
if (i == 10) {
// Here, we generate an exception
throw Exception('test');
}
db.store("transaction_$i", "here is a transaction_$i");
}
trans.commit();
} catch (e) {
// the transaction is rolled back here
trans.rollback();
}
You can also use iterators to iterate over all data:
for (var entry in db.cursor()) {
var content = '${entry.key} => ${entry.value}';
debugPrint(content);
}
UnQLite db = UnQLite.open("${appDocDir.path}/test2.db");
var users = db.collection("users");
// Create a collection
users.create();
// Save JSON
users.store(jsonDecode('''
{
"title": "test json string",
"author": [
"arcticfox1919"
],
"year": 2022,
"like": "flutter"
}
'''));
users.store({'name': 'Mickey', 'age': 17});
users.store([
{'name': 'Alice', 'age': 18},
{'name': 'Bruce', 'age': 19},
{'name': 'Charlie', 'age': 20},
]);
// Get all
print(users.all());
// print(users.fetch(0));
// print(users.fetch(1));
// print(users.fetch(2));
// print(users.errorLog());
print(users.creationDate());
print(users.len());
print(users.fetchCurrent());
// Delete all
users.drop();
db.close();
- Faster than Hive and takes up less memory
- Can support JSON documents
What are the drawbacks? Because dart ffi is used, it cannot be used on the web.
Below is some performance test data, the percentage of memory is not listed here, but I'm sure unqlite only uses much less memory:
UnQLite:
UnQLite init:1 ms
write 100,000 entries :611 ms
fetch 100,000 entries :370 ms
seek 100,000 entries :215 ms
iterate 100,000 entries :225 ms
transaction rollback :39 ms
Hive:
Hive init:48 ms
put 100,000 entries :807 ms
get 100,000 entries :290 ms
Here is the code for testing, both running in profile mode on the same phone:
testUnQLite() async {
var appDocDir = await getApplicationDocumentsDirectory();
final start = DateTime.now().millisecondsSinceEpoch;
UnQLite db = UnQLite.open("${appDocDir.path}/test.db");
final t1 = DateTime.now().millisecondsSinceEpoch;
for (var i = 0; i < 100000; i++) {
db.store("my_key_$i", "Here is a value for testing—$i");
}
final t2 = DateTime.now().millisecondsSinceEpoch;
for (var i = 0; i < 100000; i++) {
var r = db.fetch<String>("my_key_$i");
// debugPrint("fetch :$r");
}
final t3 = DateTime.now().millisecondsSinceEpoch;
var cursor = db.cursor();
for (var i = 0; i < 100000; i++) {
cursor.seek('my_key_$i');
// debugPrint('=> ${cursor.key} => ${cursor.value}');
}
final t4 = DateTime.now().millisecondsSinceEpoch;
var count = 0;
for (var entry in db.cursor()) {
count++;
var content = '${entry.key} => ${entry.value}';
// debugPrint(content);
}
print('count => $count');
final t5 = DateTime.now().millisecondsSinceEpoch;
var trans = db.transaction().begin();
try {
for (var i = 0; i < 100000; i++) {
if (i == 10) {
throw Exception('test');
}
db.store("transaction_$i", "here is a transaction_$i");
}
trans.commit();
} catch (e) {
trans.rollback();
}
final t6 = DateTime.now().millisecondsSinceEpoch;
debugPrint("UnQLite init:${t1-start} ms");
debugPrint("write 100,000 entries :${t2-t1} ms");
debugPrint("fetch 100,000 entries :${t3-t2} ms");
debugPrint("seek 100,000 entries :${t4-t3} ms");
debugPrint("iterate 100,000 entries :${t5-t4} ms");
debugPrint("transaction rollback :${t6-t5} ms");
db.close();
}
testHive() async {
var appDocDir = await getApplicationDocumentsDirectory();
var path = appDocDir.path;
final start = DateTime.now().millisecondsSinceEpoch;
Hive.init(path);
var box = await Hive.openBox('testBox');
final t1 = DateTime.now().millisecondsSinceEpoch;
for (var i = 0; i < 100000; i++) {
box.put("my_key_$i", "here is a transaction_$i");
}
final t2 = DateTime.now().millisecondsSinceEpoch;
for (var i = 0; i < 100000; i++) {
var name = box.get('my_key_$i');
}
final t3 = DateTime.now().millisecondsSinceEpoch;
box.close();
debugPrint("Hive init:${t1-start} ms");
debugPrint("put 100,000 entries :${t2-t1} ms");
debugPrint("get 100,000 entries :${t3-t2} ms");
}