Today I started experimenting with Firebase Live database. Maybe I'm thinking too much in sql terms. But what I want to do is get a record from my database where a value equals a variable with flutter. My table looks like this:
What I'm trying to achieve is something like this:
FirebaseDatabase.instance.reference().child('users').where('User_id', 1508)
Like I said. I'm a complete beginner when it comes to Live Databases.
I hope someone can help me with this issue I'm having.
Kind regards,
Namanix
According to firstore docs
Firestore.instance
.collection('talks')
.where("topic", isEqualTo: "flutter")
.snapshots()
.listen((data) =>
data.documents.forEach((doc) => print(doc["title"])));
If you have the user id in a variable for example called:
String uid = currentUser.uid;
then you can do the following:
FirebaseDatabase.instance.reference().child('users/$uid')
Update
I think this is what you are asking about
FirebaseDatabase.instance
.reference().child("users")
.orderByChild("User_id")
.equalTo($this.userId)
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FutureBuilder<QuerySnapshot>(
future: FirebaseFirestore
.instance
.collection('users')
.where("user_id", isEqualTo: FirebaseAuth.instance.currentUser!.uid)// π Your where condition here
.get(),
builder: (_, snapshot) {
if (snapshot.hasError) return Text('Error = ${snapshot.error}');
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text("Loading");
}
return ListView(
children: snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data = document.data()! as Map<String, dynamic>;
return ListTile(
title: Text(data['avatar']), // π Your valid data here
);
}).toList());
},
)),
);
}
Also refer: How to use StreamBuilder and FutureBuilder for single and multiple documents
Related
I m trying to snapshot the Collection of users and I want to check if the user has the field or not
If the users has then show this
If user doesnβt have then show this
This is the code i got so far.
class _HalfScreenState extends State<HalfScreen> {
final userUid = FirebaseAuth.instance.currentUser!.uid;
#override
Widget build(BuildContext context) {
return StreamBuilder<DocumentSnapshot?>(
stream: FirebaseFirestore.instance
.collection("users")
.doc(userUid)
.snapshots(),
builder: (context, snapshot) {
if (snapshot.data != null) {
return const Text("Loading...");
}
return Text(
(snapshot.data as DocumentSnapshot)['groupId'],
),
});
}
}
Step by step that'd be:
Get the data from the document as a Map.
Check if the map contains a key for the field you're looking for.
In code that'd be something like this:
// π Indicate the type of the data in the document
return StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance
.collection("users")
.doc(userUid)
.snapshots(),
builder: (context, snapshot) {
if (snapshot.data != null) {
return const Text("Loading...");
}
// π Get the data (Map<String, dynamic>
var data = snapshot.data.data();
return Text(
// π Check if the field is tere
data.containsKey('groupId') ? 'Yes, it's there' : 'Nope, field not found'
),
}
);
In my flutter project, I need to access the realtime database to get the name of the user when they create a post. This is the code I'm working with:
class PostScreen extends StatelessWidget {
static const String idScreen = 'post';
final String name1 = FirebaseDatabase.instance
.reference()
.child('users')
.child(FirebaseAuth.instance.currentUser.uid)
.child('name1')
.toString();
final String name2 = FirebaseDatabase.instance
.reference()
.child('users')
.child(FirebaseAuth.instance.currentUser.uid)
.child('name2')
.toString();
#override
Widget build(BuildContext context) {
return Scaffold(
body: FlatButton(
child: Text('Create Post'),
onPressed: () {
MainScreen.posts.add(Post(
name1: name1,
name2: name2,
));
Navigator.pushNamed(context, MainScreen.idScreen);
},
),
);
}
}
class Post extends StatelessWidget {
String name1 = '';
String name2 = '';
Post({#required name1, #required name2});
#override
Widget build(BuildContext context) {
return Card(
child: Row(
children: [
Text(name1),
Text(" and "),
Text(name2),
],
),
);
}
}
What happens though is that the name is left blank and just creates a card that says " and ". What could I be doing wrong?
Your code doesn't read anything from the database yet. For that to happen you need to call the once() stream, or listen to the onValue or onChild... streams.
I also recommend simplifying your problem before continuing. So instead of reading the data for the current user (which requires that you have a current user), simply write some hard-coded data at a known location in the database and read that first. That should look something like this:
final DatabaseReference ref = FirebaseDatabase.instance
.reference()
.child('test');
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: ref.onValue,
builder: (BuildContext context, snapshot) {
if(snapshot.hasData) => return Text(snapshot.value);
else if(snapshot.hasError) => return Text("Error");
else return Text("No data (yet)");
}
);
}
There may be syntax errors in this code, so treat it as an example of an approach instead of a copy/paste solution please. If you find any of such errors, please try to solve them on your own - and edit the answer with any fixes.
Also see:
How To Use Firebase RTDB with Flutter Stream
more of these search results
You should be able to do something like this:
DatabaseReference myRef = FirebaseDatabase.instance
.reference()
.child('users')
.child(FirebaseAuth.instance.currentUser.uid)
.child('name1');
StreamBuilder(
stream: myRef.onValue,
builder: (context, AsyncSnapshot<Event> snap) {
if (snap.hasData && !snap.hasError && snap.data.snapshot.value != null) {
// Handle snapshot data
}
}
If you don't need to continue getting changes from the location you can probably use a future builder and .once() method. Don't have experience with that myself though.
So I need to get access to a piece of data called groupId which will be used as a doc path for a collection called Members that I will be used to retrieve data from and put in a list. The problem is that it requires an async which I don't know where to put as I get errors. Here's the code:
#override
Widget build(BuildContext context) {
final CollectionReference users = firestore.collection('UserNames');
final String uid = auth.currentUser.uid;
final result = await users.doc(uid).get(); //This await requires an async but I don't how to do that
final groupId = result.data()['groupId'];
// <1> Use FutureBuilder
return FutureBuilder<QuerySnapshot>(
// <2> Pass `Future<QuerySnapshot>` to future
future: FirebaseFirestore.instance.collection('Groups').doc(groupId).collection('Members').get(), //Once the async problem is solved i will be able to save the groupId as. variable to be used in my doc path to access this collection. How do I do this?
builder: (context, snapshot) {
if (snapshot.hasData) {
// <3> Retrieve `List<DocumentSnapshot>` from snapshot
final List<DocumentSnapshot> documents = snapshot.data.docs;
return ListView(
children: documents
.map((doc) => Card(
child: ListTile(
title: Text(doc['displayName']),
subtitle: Text(doc['plastics'].toString()),
),
))
.toList());
} else if (snapshot.hasError) {
return Text('Its Error!');
}
});
}
Wrap your FutureBuilder in another FutureBuilder.
users.doc(uid).get() returns a Future. If you are using it in a widget, you use FutureBuilder.
await and futureBuilder do the similar things
#override
Widget build(BuildContext context) {
final CollectionReference users = firestore.collection('UserNames');
final String uid = auth.currentUser.uid;
return FutureBuilder(
future: users.doc(uid).get(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final result = snapshot.data;
final groupId = result.data()['groupId'];
return FutureBuilder<QuerySnapshot>(
// <2> Pass `Future<QuerySnapshot>` to future
future: FirebaseFirestore.instance
.collection('Groups')
.doc(groupId)
.collection('Members')
.get(), //Once the async problem is solved i will be able to save the groupId as. variable to be used in my doc path to access this collection. How do I do this?
builder: (context, snapshot) {
if (snapshot.hasData) {
// <3> Retrieve `List<DocumentSnapshot>` from snapshot
final List<DocumentSnapshot> documents = snapshot.data.docs;
return ListView(
children: documents
.map((doc) => Card(
child: ListTile(
title: Text(doc['displayName']),
subtitle: Text(doc['plastics'].toString()),
),
))
.toList());
} else if (snapshot.hasError) {
return Text('Its Error!');
}
});
}
});
}
I ma getting a null return on a stream query. The funny thing is that data came through but on processing it to use it in the app it gets lost somewhere.I know i probably made a silly mistake somewhere yet i've been looking at this issue for three days now. Please help.
Here is the stream
Stream <SellerProfile> get sellerProfile {
return sellerProfileCollection.document(uid).snapshots()
.map(yieldSellerProfile);
}
SellerProfile yieldSellerProfile(DocumentSnapshot snapshot) {
print(snapshot.data['shopName']);
return SellerProfile(
shopName: snapshot.data['shopName'] ?? '',
phone: snapshot.data['phone']??'',
credit: snapshot.data['credit'] ?? '',
posts: snapshot.data['posts'] ?? '',
sales: snapshot.data['sales'] ?? '',
avatarUrl: snapshot.data['avatarUrl'] ?? '',
location:snapshot.data['location'] ?? '',
rating: snapshot.data['rating'] ?? '',
joinedDate: snapshot.data['joinedDate'] ?? '',
);
}
My idea is that after querying the stream sellerProfile i want to map it into a custom model to use it in the app.
As in the code, i print the snapshot.data['shopName'] before it is processed and i get the output
I/flutter ( 1008): Soko
which means the data arrives from firestore but as i try to access the data on my frontend i receive a null
Here is the frontend
Widget build(BuildContext context) {
final AuthService _auth = AuthService();
final user = Provider.of<User>(context);
return StreamBuilder<SellerProfile>(
stream: SellerDatabaseService(uid: user.uid).sellerProfile,
builder: (context, snapshot) {
SellerProfile profile=snapshot.data;
print(profile);
return Scaffold(
backgroundColor: Colors.white,
appBar: header(context,strTitle: "Profile"),
body: SingleChildScrollView(),
);
}
);
}
and here is the output when i try to print the profile
I/flutter ( 1008): null
Where am i going wrong? Thanks in advance!
I go the issue. I was trying to build the stream with stream builder instead of returning it from a provider.
So i changed this...
Widget build(BuildContext context) {
final AuthService _auth = AuthService();
final user = Provider.of<User>(context);
return StreamBuilder<SellerProfile>(
stream: SellerDatabaseService(uid: user.uid).sellerProfile,
builder: (context, snapshot) {
SellerProfile profile=snapshot.data;
print(profile);
return Scaffold(
backgroundColor: Colors.white,
appBar: header(context,strTitle: "Profile"),
body: SingleChildScrollView(),
);
}
);
}
To this...
return StreamProvider<BuyerProfile>.value(
value: BuyerDatabaseService(uid: user.uid).buyerProfile,
builder: (context, snapshot) {
BuyerProfile profile=Provider.of<BuyerProfile>(context);
if(profile!=null){
return Scaffold(...
You're not checking if the snapshot has data yet. Add a check for this with the hasData property of the AsyncSnapshot:
return StreamBuilder<SellerProfile>(
stream: SellerDatabaseService(uid: user.uid).sellerProfile,
builder: (context, snapshot) {
if(snapshot.hasError) {
return Text(snapshot.error.toString());
}
if(!snapshot.hasData) {//Check if the snapshot actually has data
return CircularProgressIndicator();
}
SellerProfile profile=snapshot.data;
print(profile);
return Scaffold(
backgroundColor: Colors.white,
appBar: header(context,strTitle: "Profile"),
body: SingleChildScrollView(),
);
}
);
Ideally you should also check if it hasError as well, and if you want more granular control over what to show, you could use the connectionState.
I am building a Flutter application and I am having trouble understanding how to implement Firestore. Out of the tutorials I have seen, I only see how to create a snapshot of an entire collection, however in my case, my collection is users, so I only need to snapshot the document of a particular user. There doesn't appear to be documentation on the Firebase docs on how to do this nor is there much documentation on the FlutterFire GitHub page. Please help!
This is the Widget I'm trying to build with StreamBuilder.
#override
Widget build(BuildContext context) {
return new StreamBuilder(
stream: Firestore.instance.collection('users').document(userId).snapshots(),
builder: (context, snapshot) {
return new ListView.builder(
itemCount: //what do I put here?,
itemBuilder: (context, index) => new Item(//And here?),
);
}
);
}
Lets say you want to create a Text with the name parameter from your document
Widget build(BuildContext context) {
String userId = "skdjfkasjdkfja";
return StreamBuilder(
stream: Firestore.instance.collection('users').document(userId).snapshots(),
builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (!snapshot.hasData) {
return Text("Loading");
}
var userDocument = snapshot.data;
return Text(userDocument["name"]);
}
);
}
This is just one instance. Creating a StreamBuilder on the document will rebuild itself every time the document itself is changed. You can try this code, and then go to your console and change the "name" value. Your app will automatically reflect the changes.
Instead of just one Text, you could build entire tree that uses data from your stream.
If you want to get just at the moment value of the document, you can do so by resolving the Future of get() method on document reference.
var document = await Firestore.instance.collection('users').document(userId).get(),
Each element should be casted to have a reference later in the code.
return new StreamBuilder<DocumentSnapshot>(
stream: Firestore.instance.collection('users').document(userId).snapshots(), //returns a Stream<DocumentSnapshot>
builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (!snapshot.hasData) {
return new Text("Loading");
}
var userDocument = snapshot.data;
return new Text(userDocument["name"]);
}
);
}
Update 2023 with null safety
class _UserInformationState extends State<UserInformation> {
final _usersStream = FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid) // π Your document id change accordingly
.snapshots();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: _usersStream,
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text("Loading");
}
Map<String, dynamic> data =
snapshot.data!.data()! as Map<String, dynamic>;
return Text(data['fullName']);
},
),
),
);
}
}