CodeBlanks Logo Icon CodeBlanks

Summary - Firestore

Combine add, snapshots and where to make a chat screen.

Chat screen

A chat screen combines add, snapshots and where. New messages are added with add, existing messages are listened to in real time via snapshots, and messages from a specific user can be filtered with where. The stream updates automatically when data changes.

await db.collection('messages').add({
  'text': msg,
  'sender': 'Ali',
});
db.collection('messages').snapshots().listen((snap) {
  for (final doc in snap.docs) {
    print(doc.data()['text']);
  }
});

Practice Write a chat flow

Get db. First add a document with data {'text': 'Merhaba', 'sender': 'Ali'} to the 'messages' collection. Then filter with where('sender', isEqualTo: 'Ali') and listen to the snapshots stream. Print the text field of the first document on each snapshot. Wait 10 milliseconds.

Starter code

main.dart
class QueryDocumentSnapshot {
  final Map<String, dynamic> data;
  QueryDocumentSnapshot(this.data);
}

class QuerySnapshot {
  final List<QueryDocumentSnapshot> docs;
  QuerySnapshot(this.docs);
}

class DocumentReference {
  final String id;
  DocumentReference(this.id);
}

class Query {
  final List<QueryDocumentSnapshot> docs;
  Query(this.docs);
  Stream<QuerySnapshot> snapshots() async* {
    yield QuerySnapshot(docs);
  }
}

class CollectionReference {
  final String name;
  final List<Map<String, dynamic>> _store;
  CollectionReference(this.name, this._store);

  Future<DocumentReference> add(Map<String, dynamic> data) async {
    _store.add(data);
    return DocumentReference('auto-${_store.length}');
  }

  Query where(String field, {required String isEqualTo}) {
    final filtered = _store
      .where((m) => m[field] == isEqualTo)
      .map((m) => QueryDocumentSnapshot(m))
      .toList();
    return Query(filtered);
  }
}

class FirebaseFirestore {
  static final FirebaseFirestore instance = FirebaseFirestore._();
  FirebaseFirestore._();
  final Map<String, List<Map<String, dynamic>>> _db = {};

  CollectionReference collection(String name) {
    _db.putIfAbsent(name, () => []);
    return CollectionReference(name, _db[name]!);
  }
}

void main() async {
  // belge ekle
  // where ile filtrele, snapshots dinle
  // her snapshot'ta ilk belgenin text alanını yazdır
}

Sample solution

main.dart
class QueryDocumentSnapshot {
  final Map<String, dynamic> data;
  QueryDocumentSnapshot(this.data);
}

class QuerySnapshot {
  final List<QueryDocumentSnapshot> docs;
  QuerySnapshot(this.docs);
}

class DocumentReference {
  final String id;
  DocumentReference(this.id);
}

class Query {
  final List<QueryDocumentSnapshot> docs;
  Query(this.docs);
  Stream<QuerySnapshot> snapshots() async* {
    yield QuerySnapshot(docs);
  }
}

class CollectionReference {
  final String name;
  final List<Map<String, dynamic>> _store;
  CollectionReference(this.name, this._store);

  Future<DocumentReference> add(Map<String, dynamic> data) async {
    _store.add(data);
    return DocumentReference('auto-${_store.length}');
  }

  Query where(String field, {required String isEqualTo}) {
    final filtered = _store
      .where((m) => m[field] == isEqualTo)
      .map((m) => QueryDocumentSnapshot(m))
      .toList();
    return Query(filtered);
  }
}

class FirebaseFirestore {
  static final FirebaseFirestore instance = FirebaseFirestore._();
  FirebaseFirestore._();
  final Map<String, List<Map<String, dynamic>>> _db = {};

  CollectionReference collection(String name) {
    _db.putIfAbsent(name, () => []);
    return CollectionReference(name, _db[name]!);
  }
}

void main() async {
  final db = FirebaseFirestore.instance;
  await db.collection('messages').add({
    'text': 'Merhaba',
    'sender': 'Ali',
  });
  db.collection('messages')
    .where('sender', isEqualTo: 'Ali')
    .snapshots()
    .listen((snap) {
      print(snap.docs.first.data()['text']);
    });
  await Future.delayed(Duration(milliseconds: 10));
}

Expected output

Merhaba

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 How is the list updated when a new message is added on the chat screen?

  • The snapshots stream automatically emits a new snapshot Correct answer
  • get is called manually
  • The list never updates
  • The app is restarted

Explanation: Since snapshots is a real-time stream, it automatically emits a new snapshot when data is added; no manual get is needed.

2 Add a message

Question
await db.collection('messages').____({
  'text': 'Merhaba',
  'sender': 'Ali',
});
Answer
await db.collection('messages').add({
  'text': 'Merhaba',
  'sender': 'Ali',
});

Explanation: To add a new message on the chat screen you use the add method; the message data is given as a Map.

3 Chat screen parts

Term Meaning
add Adds a message
snapshots Listens to messages
where Filters by sender
doc.data()['text'] Message text

All lessons in Advanced