ds_easy_db_firebase_realtime 1.0.1
ds_easy_db_firebase_realtime: ^1.0.1 copied to clipboard
Firebase Realtime Database implementation for DS-EasyDB. Provides real-time data synchronization with streaming support.
EasyDB Firebase Realtime #
Firebase Realtime Database implementation for DS-EasyDB (https://github.com/Dragon-InterActive/ds_easy_db). Provides real-time data synchronization with streaming support for Flutter applications.
Features #
- Real-Time Synchronization: Instant data updates across all connected clients
- Streaming Support: Built-in reactive streams for live data
- Offline Support: Automatic data caching and synchronization when back online
- Low Latency: Optimized for speed with minimal delay
- JSON-Based: Simple JSON structure for easy data modeling
- Cross-Platform: Works on iOS, Android, Web, macOS, Windows
Installation #
Add to your pubspec.yaml:
dependencies:
ds_easy_db: ^1.0.1
ds_easy_db_firebase_realtime: ^1.0.1
firebase_core: ^4.2.1 # Required for Firebase initialization
Firebase Setup #
1. Create Firebase Project #
- Go to Firebase Console
- Create a new project or select existing one
- Enable Realtime Database in the "Build" section
- Choose a database location (closest to your users)
- Start in test mode (configure security rules later)
2. Install Firebase CLI #
npm install -g firebase-tools
dart pub global activate flutterfire_cli
3. Configure Firebase #
# Login to Firebase
firebase login
# Configure FlutterFire
flutterfire configure
This creates firebase_options.dart with your Firebase configuration.
Usage #
Basic Setup #
In your ds_easy_db_config.dart:
import 'package:ds_easy_db/ds_easy_db.dart';
import 'package:ds_easy_db_firebase_realtime/ds_easy_db_firebase_realtime.dart';
import 'firebase_options.dart'; // Your generated Firebase config
class EasyDBConfig {
static DatabaseStreamRepository get stream => FirebaseRealtimeDatabase(
options: DefaultFirebaseOptions.currentPlatform,
);
// ... other configurations
}
In your main.dart:
import 'package:flutter/material.dart';
import 'package:ds_easy_db/ds_easy_db.dart';
import 'ds_easy_db_config.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Configure EasyDB
db.configure(
stream: EasyDBConfig.stream,
// ... other configurations
);
// Firebase is automatically initialized when db.init() is called
await db.init();
runApp(MyApp());
}
Examples #
Watch Single Document #
// Listen to user changes in real-time
db.stream.watch('users', 'user123').listen((userData) {
if (userData != null) {
print('User updated: ${userData['name']}');
} else {
print('User deleted');
}
});
Watch Entire Collection #
// Listen to all users
db.stream.watchAll('users').listen((allUsers) {
if (allUsers != null) {
print('Total users: ${allUsers.length}');
}
});
Watch with Query #
// Watch only online users
db.stream.watchQuery('users',
where: {'online': true}
).listen((onlineUsers) {
print('Online users: ${onlineUsers.length}');
for (var user in onlineUsers) {
print('- ${user['name']} is online');
}
});
Write Data #
// Create or update user
await db.stream.set('users', 'user123', {
'name': 'John Doe',
'online': true,
'lastSeen': DatabaseRepository.serverTS, // Uses ServerValue.timestamp
});
// Update specific fields
await db.stream.update('users', 'user123', {
'online': false,
'lastSeen': DatabaseRepository.serverTS,
});
// Delete user
await db.stream.delete('users', 'user123');
Real-Time Chat Example #
class ChatScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamBuilder<List<Map<String, dynamic>>>(
stream: db.stream.watchQuery('messages',
where: {'roomId': 'room123'}
),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
}
final messages = snapshot.data!;
return ListView.builder(
itemCount: messages.length,
itemBuilder: (context, index) {
final message = messages[index];
return ListTile(
title: Text(message['text']),
subtitle: Text(message['sender']),
);
},
);
},
);
}
}
// Send message
Future<void> sendMessage(String text) async {
await db.stream.set('messages', DateTime.now().millisecondsSinceEpoch.toString(), {
'text': text,
'sender': 'user123',
'roomId': 'room123',
'timestamp': DatabaseRepository.serverTS,
});
}
Presence System #
// Set user online
await db.stream.set('presence', userId, {
'online': true,
'lastSeen': DatabaseRepository.serverTS,
});
// Watch user presence
db.stream.watch('presence', userId).listen((presence) {
if (presence?['online'] == true) {
print('User is online');
} else {
print('User was last seen at: ${presence?['lastSeen']}');
}
});
// Set offline on disconnect (use Firebase SDK directly)
FirebaseDatabase.instance
.ref('presence/$userId')
.onDisconnect()
.update({'online': false, 'lastSeen': ServerValue.timestamp});
Live Counter #
class LiveCounterWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamBuilder<Map<String, dynamic>?>(
stream: db.stream.watch('counters', 'visitors'),
builder: (context, snapshot) {
final count = snapshot.data?['count'] ?? 0;
return Column(
children: [
Text('Visitors: $count'),
ElevatedButton(
onPressed: () async {
await db.stream.update('counters', 'visitors', {
'count': count + 1,
});
},
child: Text('Increment'),
),
],
);
},
);
}
}
Live Location Tracking #
// Update location
await db.stream.update('locations', userId, {
'lat': 52.5200,
'lng': 13.4050,
'timestamp': DatabaseRepository.serverTS,
});
// Watch all locations
db.stream.watchAll('locations').listen((locations) {
if (locations != null) {
locations.forEach((userId, location) {
print('$userId is at: ${location['lat']}, ${location['lng']}');
});
}
});
Security Rules #
Configure Firebase Realtime Database security rules in Firebase Console:
{
"rules": {
"users": {
"$uid": {
".read": "auth != null",
".write": "auth != null && auth.uid == $uid"
}
},
"messages": {
".read": "auth != null",
".write": "auth != null"
},
"presence": {
"$uid": {
".read": true,
".write": "auth != null && auth.uid == $uid"
}
}
}
}
Data Structure Best Practices #
✅ Good Structure (Flat & Denormalized) #
// Users
await db.stream.set('users', 'user123', {
'name': 'John',
'email': 'john@example.com',
});
// User posts (separate collection)
await db.stream.set('posts/user123', 'post1', {
'title': 'Hello World',
'content': 'My first post',
});
❌ Bad Structure (Deeply Nested) #
// Don't do this!
await db.stream.set('users', 'user123', {
'name': 'John',
'posts': {
'post1': {
'title': 'Hello',
'comments': {
'comment1': {...} // Too deep!
}
}
}
});
Offline Support #
Realtime Database automatically caches data:
// Enable offline persistence (enabled by default)
FirebaseDatabase.instance.setPersistenceEnabled(true);
// Data is automatically synced when connection is restored
await db.stream.set('users', 'user123', {
'name': 'John',
'lastUpdated': DatabaseRepository.serverTS,
});
Performance Tips #
- Keep Data Flat: Avoid deep nesting (max 32 levels)
- Denormalize Data: Duplicate data for faster reads
- Use Indexing: Define indexes in Firebase Console for queries
- Limit Listeners: Don't watch entire large collections
- Use Priority: Set priorities for sorting without reading all data
Realtime vs Firestore #
| Feature | Realtime Database | Firestore |
|---|---|---|
| Data Model | JSON tree | Document collections |
| Latency | Lower | Slightly higher |
| Queries | Limited | More powerful |
| Offline | Automatic | Automatic |
| Pricing | Per GB | Per operation |
| Best For | Real-time apps | Complex queries |
When to Use #
✅ Perfect for Realtime Database #
- Chat applications
- Live tracking (location, status)
- Collaborative editing
- Real-time gaming
- Presence systems
- Live counters/metrics
- Social feeds
❌ Consider Firestore Instead #
- Complex queries
- Large datasets
- Document-based data
- Advanced filtering
- Transactions
Limitations #
- Data Size: 1GB free tier
- Connections: 100 simultaneous free tier
- Depth: Maximum 32 levels of nesting
- Query: Limited to single orderBy per query
- Write Size: Maximum 256MB per write
Pricing #
Firebase Realtime Database offers a generous free tier:
- Storage: 1GB
- Downloads: 10GB/month
- Connections: 100 simultaneous
See Firebase Pricing for details.
Troubleshooting #
Permission Denied #
// Error: PERMISSION_DENIED
// Solution: Update security rules in Firebase Console
Data Not Syncing #
// Check connection status
FirebaseDatabase.instance.ref('.info/connected').onValue.listen((event) {
if (event.snapshot.value == true) {
print('Connected to Firebase');
} else {
print('Disconnected from Firebase');
}
});
Slow Queries #
// Use indexing - define in Firebase Console:
// {
// "rules": {
// "users": {
// ".indexOn": ["name", "age"]
// }
// }
// }
License #
BSD-3-Clause License - see LICENSE file for details.
Copyright (c) 2025, MasterNemo (Dragon Software)
Feel free to clone and extend. It's free to use and share.