Flutter Fire Store - Assigning individual document fields to variables - flutter

I'm attempting to show a user's profile image on their home page by pulling the user's 'imageUrl' from their Fire Store document. I already have the app setup to where the user can upload a new image which updates the 'imageUrl' in Fire Store, but I don't know how to have the 'imageUrl' as a variable so I can show it on the app screen.
I've been reading documentation online but It seems over simplified or out of date. I've tried using StreamBuilder, but it pulls the data from every user in the database instead of for a single user. I just need to know how to pull this one value and use it as a variable in my dart code using "getString()" with a document reference or the collection reference I already have, thank you.
class _UserPageState extends State<UserPage> {
User user = auth.currentUser!;
final CollectionReference collectionReference = FirebaseFirestore.instance.collection('users');
// Get profileImageUrl from users userDoc
String imageUrl = 'test'; // this should be the users imageUrl
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'${user.email}'), // this is being pulled from authentication not firestore
),
body: Center(
child: Column(
children: [
// --------------------------- I tried using a stream builder here ---------------------
StreamBuilder(
stream: collectionReference.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return const Text(
'Something went wrong.'); // A: use incase the data does not load
}
final data = snapshot.requireData;
return ListView.builder(
shrinkWrap: true,
itemCount: data.size,
itemBuilder: (context, index) {
return Text(
// A: Stream builder will update with all of the users email addresses, I want this for one user exclusively
'My email is ${data.docs[index]['email']}');
},

collection('users')
.where("uid", isEqualTo: uid)
.snapshots(),
To filter the data in firestore collection use "where". Store the user uid in offline and query it by where using the stored uid

You can use the following function to get single data from stream.
Stream<UserModel> getSingleStreamData({String? uId}) {
return ref!.where(CommonKeys.id, isEqualTo: uId).snapshots().map((value) => value.docs.first.data());}

Related

how to get document id index on firestore with flutter onTap method

I am trying to get the document ID. I don't know if it is the right way, but until now I could manage to get all the IDs.
Then I am trying to get the document ID index so I can open the category with onTap and show the category products.
I have tried with map, forEach, etc... but nothing.
return Scaffold(
body: StreamBuilder(
stream: firestore.snapshots(),
builder:(context, snapshot){
if (snapshot.connectionState == ConnectionState.waiting)
return Center(child: CircularProgressIndicator());{
final document = snapshot.data?.docs;
return ListView.builder(
itemCount: document?.length,
itemBuilder: (context, index) {
return Center(
child: Column(
children: [
InkWell(
onTap: (){
FirebaseFirestore.instance.collection('prova').get()
.then((QuerySnapshot querySnapshot) {
querySnapshot.docs.map((doc) {
print(doc.id);
var docId = doc.id;
Navigator.push(context, MaterialPageRoute(builder: (context)=>
CategoriesPage(document: document[index]['name'], docId: docId)));
});
});
As I mentioned in my comment, the way FireStore allows you to store data is alternating between collections and docs. That's to say you can't put another doc into a doc, and another collection within a collection. You can only put docs in a collection, and then subcollections within a doc, etc, etc.
I'm unaware of your data structuring needs, however I'd suggest something like this:
When a user creates a category, simply add it to their doc, and then any products within the category could be placed into a sub-collection under that category. Let me know if that could work for you.

Why Won't This StreamBuilder Display Data without Restarting the App?

I'm trying to get a Flutter project to display a simple list of items returned from the Firebase Realtime Database. The code mostly works, but I have to restart the app each time I log out and log back in as a different user, which isn't what I'm looking for. I need the user's data to appear when they log in. I don't quite understand what all is happening here (I stumbled across a functional solution after several days of trial and error and googling), but I thought a Stream was more or less a 'live' stream of data from a particular source.
EDIT: kPAYEES_NODE is a constant stored elsewhere that resolves to 'users/uid/payees' in the RTDB:
import 'package:firebase_database/firebase_database.dart';
import 'auth_service.dart';
final DatabaseReference kUSER_NODE =
FirebaseDatabase.instance.ref('users/${AuthService.getUid()}');
final DatabaseReference kPAYEES_NODE = kUSER_NODE.child('payees');
Here's the code in question:
class DashboardPage extends StatelessWidget {
const DashboardPage({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(...),
body: StreamBuilder(
stream: kPAYEES_NODE.onValue,
builder: (context, snapshot) {
final payees = <Payee>[];
if (!snapshot.hasData) {
return Center(child: Column(children: const [Text('No Data')]));
} else {
final payeeData =
(snapshot.data!).snapshot.value as Map<Object?, dynamic>;
payeeData.forEach((key, value) {
final dataLast = Map<String, dynamic>.from(value);
final payee = Payee(
id: dataLast['id'],
name: dataLast['name'],
note: dataLast['note'],
);
payees.add(payee);
});
return ListView.builder(
shrinkWrap: true,
itemCount: payees.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(
payees[index].name,
style: const TextStyle(color: Colors.white),
),
subtitle: Text(
payees[index].id,
style: const TextStyle(color: Colors.white),
),
);
});
}
},
),
floatingActionButton: (...),
);
}
}
That's because you only get the UID of the current once in your code, here:
FirebaseDatabase.instance.ref('users/${AuthService.getUid()}')
And by the time this line runs, the AuthService.getUid() has a single value. Instead, the code needs to be reevaluated any time a users signs in or out of the app.
In an app where the user can sign in and out, the UID values are a stream like the one exposed by FirebaseAuth.instance.authStateChanges() as shown in the Firebase documentation on getting the current user. You can wrap the stream that is returned by authStateChanges() in a StreamBuilder, and then create the database reference inside of that builder, to have it respond to changes in the authentication state.

Flutter Firestore how to implement notification panel like facebook/linkedin?

Looking to create a notification page that display all the events of user interaction like below
how can i track document update in realtime, e.g. new comment added to a post, status update from pending to accept etc .. ?
Is there any firestore function available ?
If the only solution is to read the updated doc and then compare the changes VS cache data, how can i achieve "real time tracking"? Since the update is initiated by another user, how to trigger the "doc update check" without any action by the notification receiver? Also this sounds like an expensive way as the app need to do a lot of read, write operations ....
You can use the snapshots()-function of the Collection/Document-Reference.
The function returns a stream which can be listened for concerningupdates within your collection or document.
Below example is from the official docs of cloud firestore for flutter:
class UserInformation extends StatelessWidget {
#override
Widget build(BuildContext context) {
CollectionReference users = FirebaseFirestore.instance.collection('users');
return StreamBuilder<QuerySnapshot>(
stream: users.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return new ListView(
children: snapshot.data.docs.map((DocumentSnapshot document) {
return new ListTile(
title: new Text(document.data()['full_name']),
subtitle: new Text(document.data()['company']),
);
}).toList(),
);
},
);
}
}

How to recover a specific data in the firestore?

I have this structure in the database:
I have a function that return the current user logged
FirebaseAuth auth = FirebaseAuth.instance;
auth.currentUser.uid;
And i want to retrieve "requisicoes" when "idUser" == auth.currentUser.uid;
Basically, the user retrieves the requests created by himself.
That's my StreamBuilder
final _controller = StreamController<QuerySnapshot>.broadcast();
FirebaseFirestore db = FirebaseFirestore.instance;
StreamBuilder<QuerySnapshot> addListenersRequests() {
final stream = db
.collection("requisicoes")
.where("usuario.idUser", isEqualTo: idUsuarioLogado)
.snapshots();
stream.listen((dados) {
_controller.add(dados);
});
return null;
}
Note: idUsuarioLogado is returning correctly currentUser
The problem is that I am getting everything in the "requisicoes" collection, when I create a new user, other users' requests appear on the screen
is there a logic problem in StreamBuilder?
As per you problem ,I think you are fetching the data of your current logged uid .But You want to retrieve the details of particulers users created(i,e documendId) . Then you have to fetch documentId first.Like
body: StreamBuilder(
stream:users.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
if(!snapshot.hasData){
return Center(
child: CircularProgressIndicator(),
);
}
return ListView(
children: snapshot.data.documents.map((document) {
return Center(
child: Container(
width: MediaQuery.of(context).size.width/2.5,
height: MediaQuery.of(context).size.height/5,
child: Text(document.id),
),
);
}).toList());
}),
You have to fetch document.id. This is your particuler user instead of this.
FirebaseAuth auth = FirebaseAuth.instance;
auth.currentUser.uid;
Note: This will return you current logged userId.
For more details gothrough thislink.
I found the answer here Firestore is ignoring the where clause in the query in flutter
My example is the same as the link above, I have two functions, one addListenersRequests() and the other getCurrentUser(), these two functions I was calling in the initState method, the problem is that getCurrentUser is async, so addListenersRequests () was being executed first, before the value of the variable idUsuarioLogado is filled.
So I merged the two functions into one, so that getCurrentUser can be executed first
Final code:
Future<StreamBuilder<QuerySnapshot>> addListenersRequests() async{
await getDataUser();
final stream = db
.collection("requisicoes")
.where("usuario.idUser", isEqualTo: idUsuarioLogado)
.snapshots();
stream.listen((dados) {
_controller.add(dados);
});
return null;
}
Now it is working correctly.
The strange thing about this story is that the firebase executes the clause and retrieves everything in the collection even when the referenced variable is null

How to get data of all users except current login user from cloud firestore?

I have a users collection where i stored usernames of all users, now i want to get usernames of users except current login user. can someone help ?
here is how i get usernames of all users :
class ChatsScreen extends StatefulWidget {
#override
_ChatsScreenState createState() => _ChatsScreenState();
}
class _ChatsScreenState extends State<ChatsScreen> {
User currentUser;
#override
void initState() {
currentUser = FirebaseAuth.instance.currentUser;
super.initState();
}
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('users')
.orderBy('addedOn', descending: true)
.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshots) {
if (!snapshots.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
itemCount: snapshots.data.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot document = snapshots.data.docs[index];
return Text(document.data()['username']);
});
});
}
}
As I understand you don't want to show the current username on the list you display by ListView widget.
return ListView.builder(
itemCount: snapshots.data.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot document = snapshots.data.docs[index];
return Text(document.data()['username']);
});
before print the Text widget here use if else statement
if the document.data()['username'] == currentUser.username
(I don't remember the parameter when get data from firebase also you can create a custom user class to take the parameters you need) don't return the Text widget else return the Text widget
Unfortunately, there is no direct way to do it in firebase yet, although firebase added the != query this month officially, not sure when it is coming to the FlutterFire repository.
So as a workaround, you'll have to compare the current logged in user's uid and then show the usernames that don't match it.
FirebaseAuth auth = FirebaseAuth.instance;
return ListView.builder(
itemCount: snapshots.data.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot document = snapshots.data.docs[index];
if(document.id == auth.currentUser.uid){
return Container(height:0);
}
return Text(document.data()['username']);
});
});
You can directly query for all the username's that are not equal to the current logged in user's uid once the firestore plugin is updated. So keep a lookout for FlutterFire repo.