아래 내용은 첨부된 이미지를 토대로 Isar의 Watchers 기능에 대해 최대한 빠짐없이 정리한 것입니다.
Dart 언어 초급자 분들도 이해하기 쉬우시도록 용어를 풀어서 설명하고, 코드 예시와 상세한 주석을 포함했습니다.
“Isar allows you to subscribe to changes in the database. You can ‘watch’ for changes in a specific object, an entire collection, or a query.”
Isar의 Watcher는 데이터베이스(DB)에 변화가 생길 때 이를 실시간으로 감지하고, 특정 동작(예: UI 갱신, 콘솔 출력, 이벤트 처리 등)을 수행할 수 있도록 도와주는 기능입니다.
Watcher는 트랜잭션이 성공적으로 커밋된 후, 실제로 해당 대상이 변경되었을 때 알림을 발생시킵니다.
“If you want to be notified when a specific object is created, updated or deleted, you should watch an object.”
아래 예시에서는 User라는 모델과, 그 모델의 id를 사용하여 특정 유저 객체의 변화를 감시합니다.
// 특정 유저 객체(ID=3)를 감시하는 스트림
Stream<User?> userChange = isar.users.watchObject(3);
// 변화가 생길 때마다 알림을 받음
userChange.listen((model) {
// model == null 이라면 해당 User가 삭제되었음을 의미
if (model == null) {
print("User changed: null (deleted)");
} else {
print("User changed: ${model.name}");
}
});
/// 실제 데이터 조작 예시
final user = User()
..id = 3
..name = "David";
// 1) 유저 추가 -> "User changed: David" 가 출력됨
await isar.writeTxn(() => isar.users.put(user));
// 2) 유저 업데이트 -> "User changed: Mark" 가 출력됨
user.name = "Mark";
await isar.writeTxn(() => isar.users.put(user));
// 3) 유저 삭제 -> "User changed: null" 이 출력됨
await isar.writeTxn(() => isar.users.delete(user.id));
id=3번 User 객체를 대상으로 변경 사항을 감시합니다. User? (nullable) model이 null로 들어옵니다.writeTxn 블록 안에서 수행해야 하며, Watcher도 트랜잭션이 커밋된 후 알림을 받습니다.fireImmediately 파라미터“There is an additional parameter
fireImmediately. If you set it totrue, Isar will immediately add the object’s current value to the stream.”
watchObject(id, fireImmediately: true) 처럼 사용하면, Watcher를 등록하자마자 해당 객체의 현재 상태를 즉시 한 번 내보내줍니다.false이며, 이 경우는 변경이 일어날 때만 알림을 받습니다.“Maybe you don’t need to receive the new value but only be notified about the change. That saves Isar from having to fetch the object.”
Lazy Watching은 객체 변경 시, 새 객체 정보가 아니라 “변경이 일어났다”라는 사실만 알림을 받는 방법입니다.
이 기능을 사용하면 DB가 실제로 객체를 다시 로드하거나, 스트림으로 전달할 필요가 없기 때문에 성능상 이점이 있을 수 있습니다.
// '값' 대신 '변경 이벤트'만 전달됨
Stream<void> userChange = isar.users.watchObjectLazy(3);
userChange.listen((_) {
print("User with id=3 changed!");
});
// 이후 동일하게 트랜잭션에서 put, delete 등을 하면
// "User with id=3 changed!" 가 로그로 출력 (model 정보 없음)
_ (매개변수)로 아무런 데이터가 들어오지 않으며, 단지 “어떤 변경이 발생했다”는 이벤트만 받습니다. isar.users.get(3) 등을 호출해야 합니다.“Instead of watching a single object, you can watch an entire collection and get notified when any object is added, updated or deleted.”
컬렉션 전체를 감시하면, 해당 컬렉션 내 어떤 객체가 추가, 수정, 삭제되어도 알림을 받을 수 있습니다.
Stream<void> userChanged = isar.users.watchLazy();
// Lazy 방식: 객체 목록이 아니라 단순 '변경 이벤트'만 전달
userChanged.listen((_) {
print("A user changed");
});
// 새로운 User 추가
final user = User()..name = "David";
await isar.writeTxn(() => isar.users.put(user));
// 결과: "A user changed" 가 출력됨
watchLazy()를 사용했으므로, 알림에서는 구체적인 User 정보가 아닌 “변경 발생”이라는 사실만 전달됩니다. isar.users.get(id) 또는 isar.users.where()... 등으로 직접 조회하면 됩니다.“It is even possible to watch entire queries. Isar does its best to only notify you when the query results actually change.”
아래 예시는 isar.users.filter()로 모든 User를 조회하는 쿼리를 감시하고, 쿼리 결과가 바뀌면 새로운 전체 목록을 스트림으로 전달받습니다.
// 모든 User를 조회하는 쿼리
Query<User> userQuery = isar.users.filter();
// initially: true -> Watcher 등록 직후, 현재 쿼리 결과도 즉시 스트림에 전달
Stream<List<User>> usersChangedStream = userQuery.watch(initially: true);
usersChangedStream.listen((users) {
// 변경된 전체 User 목록이 리스트로 전달됨
print("User list changed! Current users: $users");
});
// 데이터 추가 예시
await isar.writeTxn(() => isar.users.put(User()..name = "Albert"));
// 출력: "User list changed! Current users: [User(name: Albert)]"
await isar.writeTxn(() => isar.users.put(User()..name = "Bob"));
// 출력: "User list changed! Current users: [User(name: Albert), User(name: Bob)]"
initially: true: Watcher를 등록하자마자 현재 쿼리 결과를 한 번 내보냅니다. “Just like
watchObjectLazy, you canwatchLazy()to get notified when the query results change but not fetch the results.”
Query<User> userQuery = isar.users.filter();
Stream<void> usersChangedLazy = userQuery.watchLazy(initially: false);
usersChangedLazy.listen((_) {
print("The user query results changed! (Lazy)");
});
// 이후 트랜잭션에서 User 추가/삭제 시
// "The user query results changed! (Lazy)"가 출력
// 단, 실제 사용자 목록을 자동으로 주지는 않음
userQuery.findAll() 등을 호출해서 직접 데이터를 가져와야 합니다.fireImmediately true로 설정 시, Watcher 등록 직후 기존 상태도 한 번 전달받을 수 있습니다. offset, limit, distinct 등이 설정되어 있어도, Isar는 가능한 한 실제 결과에 변화가 있을 때만 알림을 발생시키려고 노력합니다. watchLazy() 대신 컬렉션 Watcher를 쓰는 방법도 고려합니다.이상으로 Isar의 Watchers를 활용하는 방법을 살펴보았습니다.
추가 궁금한 점이 있으시면 언제든 질문해 주세요!