Isar Plus

Create, Read, Update, Delete

Master CRUD operations with Isar Plus

Create, Read, Update, Delete

Learn how to manipulate your Isar collections with CRUD operations.

Opening Isar

Before you can do anything, you need an Isar instance. Each instance requires a directory with write permission.

main.dart
import 'package:isar_plus/isar_plus.dart';
import 'package:path_provider/path_provider.dart';

void main() async {
  final dir = await getApplicationDocumentsDirectory();
  final isar = Isar.open(
    schemas: [RecipeSchema, UserSchema],
    directory: dir.path,
  );
}

You can open multiple instances with different names using the name parameter.

Configuration Options

ConfigDescription
nameOpen multiple instances with distinct names. Default: "default"
directoryStorage location. Use Isar.sqliteInMemory for in-memory database
maxSizeMibMaximum size in MiB. Default: 2048
relaxedDurabilityTrade durability for performance
final isar = Isar.open(schemas: [UserSchema]);
final isar = Isar.open(
  schemas: [UserSchema],
  name: 'myInstance',
  directory: '/custom/path',
  maxSizeMiB: 512,
);
final isar = Isar.open(
  schemas: [UserSchema],
  directory: Isar.sqliteInMemory,
);

Create (Insert)

Create an Object

final user = User()
  ..name = 'Jane Doe'
  ..age = 28
  ..email = 'jane@example.com';

Insert with Write Transaction

await isar.writeAsync((isar) async {
  isar.users.put(user);
});

Use collection.autoIncrement() to get an auto-incrementing ID when creating objects.

Bulk Insert

final users = [
  User()..name = 'Alice'..age = 25,
  User()..name = 'Bob'..age = 30,
  User()..name = 'Charlie'..age = 35,
];

await isar.writeAsync((isar) async {
  isar.users.putAll(users);
});

Always use write transactions for data modifications!

Read (Query)

Get by ID

final user = await isar.users.get(1);
if (user != null) {
  print('Found: ${user.name}');
}

Get Multiple by IDs

final users = await isar.users.getAll([1, 2, 3]);

Get All

final allUsers = await isar.users.where().findAllAsync();

Find First

final firstUser = await isar.users.where().findFirstAsync();

Count

final count = await isar.users.countAsync();
print('Total users: $count');

Update

// Get the object
final user = await isar.users.get(1);

if (user != null) {
  // Modify it
  user.name = 'Updated Name';
  user.age = 30;
  
  // Save changes
  await isar.writeAsync((isar) async {
    isar.users.put(user);
  });
}
await isar.writeAsync((isar) async {
  final user = await isar.users.get(1);
  if (user != null) {
    user.age = (user.age ?? 0) + 1;
    isar.users.put(user);
  }
});
await isar.writeAsync((isar) async {
  final adults = isar.users
    .where()
    .ageGreaterThan(18)
    .findAll();
  
  for (var user in adults) {
    user.verified = true;
    isar.users.put(user);
  }
});

The put method acts as upsert - it inserts if the ID doesn't exist, updates if it does.

Delete

Delete by ID

await isar.writeAsync((isar) async {
  final success = isar.users.delete(1);
  print('Deleted: $success');
});

Delete Multiple by IDs

await isar.writeAsync((isar) async {
  final count = isar.users.deleteAll([1, 2, 3]);
  print('Deleted $count users');
});

Delete Object

await isar.writeAsync((isar) async {
  final user = await isar.users.get(1);
  if (user != null) {
    isar.users.delete(user.id);
  }
});

Delete All

await isar.writeAsync((isar) async {
  isar.users.clear();
});

Be careful with clear() - it deletes all records in the collection!

Delete with Filter

await isar.writeAsync((isar) async {
  final deletedCount = isar.users
    .where()
    .ageLessThan(18)
    .deleteAll();
  print('Deleted $deletedCount users');
});

Transactions

All write operations must be wrapped in a transaction:

await isar.writeAsync((isar) async {
  // Create
  final user = User()..name = 'Test';
  isar.users.put(user);
  
  // Update
  user.name = 'Updated';
  isar.users.put(user);
  
  // Delete
  isar.users.delete(user.id);
  
  // All operations are atomic
});

If an error occurs, all changes in the transaction are rolled back automatically.

Read Transactions

For better performance with multiple reads:

final results = await isar.readAsync((isar) async {
  final users = isar.users.where().findAll();
  final count = isar.users.count();
  return {'users': users, 'count': count};
});

Best Practices

  1. Use Bulk Operations

    // ✅ Good - Single transaction
    await isar.writeAsync((isar) async {
      isar.users.putAll(manyUsers);
    });
    
    // ❌ Bad - Multiple transactions
    for (var user in manyUsers) {
      await isar.writeAsync((isar) async {
        isar.users.put(user);
      });
    }
  2. Minimize Transaction Scope

    // ✅ Good
    final data = prepareData();
    await isar.writeAsync((isar) async {
      isar.users.putAll(data);
    });
    
    // ❌ Bad
    await isar.writeAsync((isar) async {
      final data = prepareData(); // Heavy operation in transaction
      isar.users.putAll(data);
    });
  3. Check Before Delete

    await isar.writeAsync((isar) async {
      final exists = await isar.users.get(id) != null;
      if (exists) {
        isar.users.delete(id);
      }
    });

Error Handling

try {
  await isar.writeAsync((isar) async {
    isar.users.put(user);
  });
} catch (e) {
  print('Error: $e');
  // Transaction is automatically rolled back
}

Next Steps

Last Update