Pass fetched value to a firestore reference to flutter's streambuilder - firebase

I'm accessing a user's favorite group which is inside groupfav in Firestore, when I get it I want to give it as part of the reference to the streambuilder stream:, so that it knows what to show in a list, but I can't pass the variable that contains the favorite group, what should I do or what am I doing wrong?
static String? userID = FirebaseAuth.instance.currentUser?.uid; // get current user id
static var taskColeccion = FirebaseFirestore.instance.collection("usuarios");
var tack = taskColeccion.doc("$userID").get().then((value) {
var groupfav = value.data()!["groupfav"]; // value i get from firestore
return groupfav;
});
late Stream<QuerySnapshot> task = FirebaseFirestore.instance
.collection("groups")
.doc(groupfav) // pass the obtained value
.collection("tareas")
.snapshots();
photo of firestore
The photo shows how Firestore's logic is and the value marked in green is what I must pass to the late Stream<QuerySnapshot> task... in its reference, logically it is a random value that I would not know. thanks for any help!
this is what the code looks like now (I took things that were not important)
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
static String? userID = FirebaseAuth.instance.currentUser?.uid;
static final taskColeccion =
FirebaseFirestore.instance.collection("usuarios");
String groupfav = '';
final tack = taskColeccion.doc("$userID").get().then((value) {
groupfav = value.data()!["groupfav"];
return groupfav;
});
Stream<QuerySnapshot> task = FirebaseFirestore.instance
.collection("groups")
.doc(groupfav) // pass the obtained value
.collection("tareas")
.snapshots();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Home"),
automaticallyImplyLeading: false,
),
body: StreamBuilder(
stream: task,
builder: (
BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot,
) {
if (snapshot.hasError) {
return const Text("error");
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text("cargando");
}
final data = snapshot.requireData;
return ListView.builder(
itemCount: data.size,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text("${data.docs[index]['titulo']}"),
subtitle: Text("${data.docs[index]['contenido']}"),
onTap: () {},
trailing: IconButton(
icon: const Icon(Icons.delete),
color: Colors.red[200],
onPressed: () {
// delete function
},
),
),
);
},
);
},
),
);
}
}

You just need to declare groupfav outside of the scope of the get method of taskColeccion;
The way you have it, the variable no longer exists by the time you're trying to pass it into the task stream.
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
static String? userID = FirebaseAuth.instance.currentUser?.uid;
static final taskColeccion =
FirebaseFirestore.instance.collection("usuarios");
String groupfav = '';
late Stream<QuerySnapshot> task;
#override
void initState() {
super.initState();
taskColeccion.doc("$userID").get().then((value) {
groupfav = value.data()!["groupfav"];
return groupfav;
});
task = FirebaseFirestore.instance
.collection("groups")
.doc(groupfav) // pass the obtained value
.collection("tareas")
.snapshots();
}

Related

Get all documents from a collection from Firestore - flutter

I am trying to get all the documents with their fields from firestore collection, but it's not working. I did this:
final _fireStore = FirebaseFirestore.instance;
Future<void> getData() async{
QuerySnapshot querySnapshot = await _fireStore.collection('addsaidas').get();;
final allData = querySnapshot.docs.map((doc) => doc.data()).toList();
print(allData);
}
But the screen still is empty. The code is running, but nothing appears.
Your code seems fine to me at first glance. For issue regarding this line
But the screen still is empty. The code is running, but nothing appears.
To display the result on screen we have to use Widgets provided by flutter.
Here’s one Example with using ListView and also printing the result in the console onPress of the FloatingActionButton :
class MyHomePage extends StatelessWidget {
MyHomePage({Key? key}) : super(key: key);
final _fireStore = FirebaseFirestore.instance;
final ref =
FirebaseFirestore.instance.collection('addsaidas').snapshots();
Future<void> getData() async {
QuerySnapshot querySnapshot =
await _fireStore.collection('addsaidas').get();
final allData = querySnapshot.docs.map((doc) => doc.data()).toList();
for (var dataMap in allData) {
if (dataMap is Map) {
// add a type check to ensure dataMap is a Map
for (var key in dataMap.keys) {
print('$key: ${dataMap[key]}'); //printing document fields using keys
}
print('----------------------');
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('My Screen')),
body: StreamBuilder<QuerySnapshot>(
stream: ref,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
final documents = snapshot.data!.docs;
return ListView.builder(
itemCount: documents.length,
itemBuilder: (context, index) {
final document = documents[index];
final data = document.data() as Map<String, dynamic>;
return ListTile(
title: Text(data['nomesaida']),
subtitle: Text(data['datasaida']),
);
},
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: getData,
backgroundColor: Colors.green,
child: const Icon(Icons.navigation),
),
);
}
}
You can print other fields as above mentioned.

Expected a value of type 'QuerySnapshot<Object?>', but got one of type '_MapStream<QuerySnapshotPlatform, QuerySnapshot<Map<String, dynamic>>>'

My goal is to get data from Firestore, then add the data to a list, the simplest way possible.
Please take note that I would like to do this without using Streambuilder because I'll be using the data list for another package which doesn't need a Streambuilder
This is the code:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
bool isFirstTime = false;
List<DocumentSnapshot> datas = [];
getData() async {
print("Getting data");
if (!isFirstTime) {
QuerySnapshot snap = (await FirebaseFirestore.instance
.collection('poll')
.snapshots()) as QuerySnapshot<Object?>;
isFirstTime = true;
setState(() {
datas.addAll(snap.docs);
});
}
}
#override
void initState() {
print("Hello");
getData();
print(datas);
super.initState();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Colors.pink[200],
body: Padding(
padding: const EdgeInsets.all(15),
child: Column(
children: const [
Text(
"Hello, world",
style: TextStyle(color: Colors.black),
),
Text(
"Hello, world",
style: TextStyle(color: Colors.black),
),
],
),
),
),
);
}
}
class Item {
Item({this.option, this.optionVotes});
final String? option;
final int? optionVotes;
}
When I print the list, it's empty. Also, I receive this error:
Console screenshot for extra reference:
.snapshot() returns Stream<QuerySnapshot<Map<String, dynamic>>> so how do you get your data without a stream, you should use .get() which returns
QuerySnapshot<Map<String, dynamic>>>
example
final querySnapshot = await await FirebaseFirestore.instance
.collection('poll')
//always good to limit
.limit(7)
.get();

How to sort a list of users through cloud firestore that contain a uid with flutter?

I am trying to make a leaderboard system for a game that I am coming up within flutter and I can't seem to find a way to sort the different users depending on their high score due to the fact that high score data is stored inside the document which is the uid?
Right now I have it set up to just display the different users in the order at which they sign in at. Thanks for all the help in advance!
// My home page
class Home extends StatelessWidget {
final AuthService _auth = AuthService();
final HighscoreData highscoreData;
Home({Key key, this.highscoreData}) : super(key: key);
#override
Widget build(BuildContext context) {
return StreamProvider<List<HighscoreData>>.value(
value: DatabaseService().brews,
child: Scaffold(
backgroundColor: Colors.brown[50],
body: HighscoreList(),
),
);
}
}
// List of different players highscores
class HighscoreList extends StatefulWidget {
#override
_HighscoreListState createState() => _HighscoreListState();
}
class _HighscoreListState extends State<HighscoreList> {
#override
Widget build(BuildContext context) {
final differentHighScores = Provider.of<List<HighscoreData>>(context) ?? [];
return ListView.builder(
itemCount: differentHighScores.length,
itemBuilder: (BuildContext context, int index){
return PlayerHighscoreTile(highscoreData: differentHighScores[index]);
},
);
}
}
// The template tile for each different highscore
class PlayerHighscoreTile extends StatelessWidget {
final HighscoreData highscoreData;
PlayerHighscoreTile({ this.highscoreData });
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(top: 8.0),
child: Card(
margin: EdgeInsets.fromLTRB(20.0, 6.0, 20.0, 0.0),
child: ListTile(
leading: CircleAvatar(
radius: 25.0,
backgroundColor: Colors.brown,
),
title: Text(highscoreData.name),
trailing: Text(highscoreData.score),
),
),
);
}
}
Here is my Database class if it helps at all
class DatabaseService {
final String uid;
DatabaseService({ this.uid });
// Collection reference
final CollectionReference<Map<String, dynamic>> brewCollection = FirebaseFirestore.instance.collection('brews');
Future updateUserData( String name, score) async {
return await brewCollection.doc(uid).set({
'score' : score,
'name' : name,
});
}
// Brew list from snapshot
List<HighscoreData> _brewListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.docs.map((doc){
return HighscoreData(
name: doc.get('name') ?? '',
score: doc.get('score') ?? '0'
);
}).toList();
}
// Get brews stream
Stream<List<HighscoreData>> get brews {
return brewCollection.snapshots().map(_brewListFromSnapshot);
}
UserData _userDataFromSnapshot(DocumentSnapshot snapshot) {
return UserData(
uid: uid,
name: snapshot.get('name'),
score: snapshot.get('score'),
);
}
// Get user document
Stream<UserData> get userData {
return brewCollection.doc(uid).snapshots().map(_userDataFromSnapshot);
}
}
I just found out how to do this by adding a sortBy() function as it grabs the different data from firebase.
Stream<List<HighscoreData>> get brews {
return brewCollection.orderBy('').snapshots().map(_brewListFromSnapshot);
}

Use stream provider inside Stateful Widget to get data for single firestore document

I have specific firestore document and I want get the value of field of that document updated every second because the field represent the number of notifications of user, But when I Looking for stream provider first time I was read we can't use it inside Stateful widget.
My Document Path
My home page code:
class Home extends StatefulWidget {
final User me;
Home({
Key key,
this.me,
}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
final Firestore _firestore = Firestore.instance;
int numberOfNotifications;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: GlobalUniversal.whiteBG,
body: Center(
child: Text(numberOfNotifications.toString()),
),
);
}
}
db.dart
class DatabaseService {
final Firestore db = Firestore.instance;
Future<UserNotification> getUserNotification(String doc) async {
var snap = await db.collection(NOTIFICATIONS_USERS_ONE_COLLECTION).document(doc).get();
return UserNotification.fromMap(snap.data);
}
Stream<UserNotification> streamUserNotifications(String doc){
return db.collection(NOTIFICATIONS_USERS_ONE_COLLECTION).document(doc).snapshots().map((snap) => UserNotification.fromMap(snap.data));
}
}
user.dart
class UserNotification {
int userNotifications;
UserNotification({this.userNotifications});
factory UserNotification.fromMap(Map data) {
return UserNotification(
userNotifications: data[UN_READ_COUNTS_FIELD] ?? 0,
);
}
}
but when I try call provider inside home page I got an error.
error: The named parameter 'stream' isn't defined. (undefined_named_parameter)
Don't use the .value if you are instantiating your stream in your provider
StreamProvider<UserNofitication>(
create: (BuildContext context) => db.streamUserNotification(widget.me.doc),
child: Center(
child: Text(numberOfNotifications.toString()),
),
),
If db.streamUserNotification(widget.me.doc) is already an instance of stream, you can use StreamProvider.value and the named parameter is value and not stream :
StreamProvider<UserNofitication>.value(
value: db.streamUserNotification(widget.me.doc),
child: Center(
child: Text(numberOfNotifications.toString()),
),
),
EDIT
to use the stream you can use the builder of the StreamProvider to read the context
StreamProvider<UserNofitication>(
create: (BuildContext context) => db.streamUserNotification(widget.me.doc),
builder: (BuildContext context, Widget child) {
numberOfNotifications = context.watch<UserNotification>()?.userNotifications ?? 0;
return Center(
child: Text(numberOfNotifications.toString()),
);
},
),

Passing Data through in a rawQuery Dart

I am getting an error message saying that genre_id is null when I pass an id (integer data) through pages. So there is something wrong when I use the index as a variable to pass on an id to the next page. How do I use index to pass it as an id for the next page?
In my sqlite database that I am using, I have a tbl_genres and a tbl_books with the book entries being tied to the genre table with a genre_id (a column in both tables).
#override
Widget build(BuildContext context) {
return Scaffold(
body: !loading ? new ListView.builder(
itemCount: genreList.length,
itemBuilder: (BuildContext context, int index) {
return new Card(
child: new ListTile(
title: new Text("${genreList[index]}"),
onTap: () {
Navigator.push(context,
MaterialPageRoute(
builder: (context) =>
BookListPage(id: index), //how to pass index as an int?
),
);
}),
);
},
) : CircularProgressIndicator(),
);
}
Here is my next page...
class BookListPage extends StatefulWidget {
int id;
BookListPage({this.id});
#override
_BookListPageState createState() => _BookListPageState();
}
class _BookListPageState extends State<BookListPage> {
bool loading;
List<Map> bookNames;
final int id;
_BookListPageState({this.id});
void initState() {
super.initState();
loading = true;
getBookData();
}
Future getBookData() async {
print(id);
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "asset_sample_sqlite.db");
ByteData data = await rootBundle.load(join("assets", "sample_sqlite.db"));
List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
await new File(path).writeAsBytes(bytes);
Database db = await openDatabase(path);
final _bookList = await db.rawQuery('SELECT book_name[] FROM tbl_books WHERE genre_id = $id'); //how to reference the passed id?
await db.close();
setState((){
loading = false;
bookNames = _bookList;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: !loading ? new ListView.builder(
itemCount: bookNames.length,
itemBuilder: (BuildContext context, int index) {
return new Card(
child: new ListTile(
title: new Text("${bookNames[index]}"),
),
);
}
) : CircularProgressIndicator(),
);
}
}
And also how do I use that index in the rawQuery to display information only relating to that id?
Modify your second page as follows:
class BookListPage extends StatefulWidget {
final int id;
BookListPage({this.id});
#override
_BookListPageState createState() => _BookListPageState();
}
class _BookListPageState extends State<BookListPage> {
bool loading;
List<Map> bookNames;
_BookListPageState();
void initState() {
super.initState();
loading = true;
getBookData();
}
Future getBookData() async {
print(widget.id);
Directory documentsDirectory = await getApplicationDocumentsDirectory();

Resources