How to access specific data from firebase - firebase

I am new to firebase and I am wondering how would you access specific data. Ill give you an example, BTW I am using flutter.
Say I am creating data like this. I making a table of posts or I guess in firebase it'd be just a json array. In this json array I have 4 pieces of data state, city, post which as of right now just represents a simple message, and also timestamp.
So my question is how can I get a filtered version of my posts with a given city and state? Is there something special you can do in firebase? or would I have to do the filtering when I am building the list view?
I know FirebaseDatabase().reference().child('posts'); can access all of the posts.
var _firebaseRef = FirebaseDatabase().reference().child('posts');
_firebaseRef.push().set({
"state": state,
"city": city,
"post": post,
"timestamp": DateTime.now().millisecondsSinceEpoch
});

The code in the question means you are adding data, not retrieving. If you want to retrieve data according to a specific city then do the following query:
var dbRef = FirebaseDatabase().reference().child('posts');
dbRef.orderByChild("city").equalTo("city_name").once();
once() returns a Future so you can use the FutureBuilder to get the data from the above query.

Use Future Builder to fetch data to listview
create getPost() method first to return qn
Future getPosts() async {
var firestore = Firestore.instance;
QuerySnapshot qn = await firestore.collection("your_collecttion_name").getDocuments();
return qn.documents;
}
after that use, future builder to fetch data
return Container(
child: FutureBuilder(
future: getPosts(),
builder: (_, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: Text("Loading..."),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (_, index) {
return Column(
children: <Widget>[
Text(
snapshot.data[index].data['your_data_field'] //name,age etc..
.toString(),
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500),
),]
),}
),
});

Related

Flutter Firestore - get only 10 docs with their id

here I'm trying to get the top 10 names only from my firebase firestore,
and I searched on how I do it with the listview that I have, but I get to nowhere.
so I thought about getting the id of my documents instead.
In my firestore I gave the top 10 documents IDs from 1 to 10, now I'm stuck and I have no idea how to do it. please help.
static int id = 1;
StreamBuilder<QuerySnapshot>(
stream: fireStore.collection(path).snapshots(),
builder: (context, snapshot) {
if(!snapshot.hasData){
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.blueAccent,
),
);
}
List<InfoBox> ancients = [];
try {
final collection = snapshot.data!.docs;
for (var collect in collection) {
final name = collect['Name'];
final image = collect['Image'];
final collectionWidget = InfoBox(
ancientName: name,
ancientImage: image
);
ancients.add(collectionWidget);
}
}catch(e){
print('problems in stream builder \n error : $e');
}
return Expanded(
child:ListView(
children: ancients,
)
);
},
);
You are probably searching for limit() function. According to the documentation:
To limit the number of documents returned from a query, use the limit method on a collection reference
You can implement it like this:
fireStore.collection(path).limit(10).snapshots();
Change your ListView to this List if else everything is ok and u are getting data in list then this will work.
ListView.builder(
itemCount: ancients.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: new Image.network(ancients[index].ancientImage),
title: new Text(ancients[index].ancientName),
)
},
)

Firebase does not retrieve fields in flutter

I'm trying to retrieve from my collection "Courses" 2 field.
Course code and Course name. My issue when retrieving is that I only managed to retrieve the first field.
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.separated(
itemCount: snapshot.data!.docs.length,
separatorBuilder: (BuildContext context, int index) =>
Divider(height: 1),
// ignore: dead_code
itemBuilder: (context, index) {
DocumentSnapshot doc = snapshot.data!.docs[index];
return ListTile(
contentPadding:
EdgeInsets.symmetric(horizontal: 30, vertical: 10),
selectedTileColor: Color(0xffE5E5E5),
title: Text.rich(
TextSpan(
text: doc["Course code"],
children: <TextSpan>[
TextSpan(text: ":"),
TextSpan(text: doc["Course name"]),
and it shows me this error:
Exception has occurred.
StateError (Bad state: field does not exist within the DocumentSnapshotPlatform)
this is my firebase
I only can retrieve course code I don't know why.
It seems like you have a problem with how Flutter and Firebase interacts with each other. I would like to suggest to check the following threadand especially the comment posted by jschnip which could solve your problem
This is probably related to recent changes in DocumentSnapshot, your
factory is looking for the data map, which used to be in doc, but nows
its in doc.data() - except DocumentID
So for your factory, one way to change it would be to adjust to:
Userr( id: doc.id, email: docdata['email'], username:
docdata['username'], url: docdata['url'], profileName:
docdata['profileName'], bio: docdata['bio'], subject1:
docdata['subject1'], subject2: docdata['subject2']
and when you call
it, you'll need to do something like:
doc.data();
newUserrr = Userr.fromDocument(doc, _docdata);

How to display a list of data from a map ? - flutter firestore

I am building an event management app. When the user buys a ticket, the ticket details are being saved in the DB like this.
Users -> (Current User ID) -> (map)bookedEvents -> eventId -> [event details]
I managed to display data of one specific event when I give one of the Event IDs as a static String like this.
StreamBuilder(
stream: FirebaseFirestore.instance
.collection('users')
.doc(_uid)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Text("Loading");
}
var userDocument = snapshot.data;
return Text(
userDocument["bookedEvents"]["KFXvCj63y7GTjQcMKfVy"]
["eventName"],
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
);
}),
But I want to display all the Event Names in a list. Could I know how? Thank you so much.
You should try something like that:
var userDocument = snapshot.data;
final List<Widget> children = [];
userDocument['bookedEvents'].forEach((key, value) {
children.add(Text(value['eventName'])); });
return Column(children: children); // or Row(children: children); or ListView(children: children);

How to fetch data from firebase realtime database in flutter?

I'm building an app in Flutter in which I have data stored in the Firebase Realtime Database. I want to fetch those data in my app.
Now, Because of breaking changes made few months ago I'm unable to find new articles or video which might help but all I find are old ones so if anyone here can help me?
variable for the list
final dbRef = FirebaseDatabase.instance.reference().child("workshops");
now for showing the data I'm trying like this
return FutureBuilder(
future: dbRef.once(),
builder: (context,AsyncSnapshot<DataSnapshot> snapshot){
if(snapshot.hasData){
workshopList.clear();
Map<dynamic, dynamic> values = snapshot.data.value;
values.forEach((key,values){
workshopList.add(values);
});
}
return ListView.builder(
shrinkWrap: true,
itemCount: workshopList.length,
itemBuilder: (BuildContext context, index){
return Card(
child: Center(
child: Column(
children: [
Text("name "+ workshopList[index].workshopName)
],
),
),
);
},
);
}
);
For declaring list I was doing like this
List<Workshop> worskshopList = [];
but what worked for me was
List<Map<dynamic,dynamic>> workshopList = [];
And now for showing the data I am using
workshopList[index].workshopName
now problem with this is that I am not referencing database's workshopname but my model class' workshop name so I am getting nowhere.
now what worked for me was
workshopList[index]["workshopname"]
now from the old list I can't use like list[index][""] it will give an error like "[]" is not defined for the list.

In Dart/Flutter, how can I find out if there is no Collection in the Firestore database?

I'd like to check if a collection (the users collection) exists in the Firestore database or not. But I cannot find any means of doing that. If the collection exists, I would like to stream its documents, otherwise an empty stream as you see in the following method
- Is there any way to find a collection exists without getting its snapshots?
- Why break; or yield* Stream.empty() hangs the stream, like an endless stream!
Stream<userInfo> getCurrentUserInfos() async* {
final String usersCollectionPath = "users";
Stream<QuerySnapshot> snapshots = Firestore.instance.collection(usersCollectionPath).snapshots();
snapshots.isEmpty.then((hasNoUserCollection) {
// Although I don't have 'users' collection
// in my database but I never reach this point!
// i.e. hasNoUserCollection is always FALSE!
if(hasNoUserCollection) {
print("users collection doesn't exist, create it!");
// next line (i.e. `break;`) hangs the tool!
// And sometimes hangs the VSCode's IDE as well, if I have a breakpoint on it!!!
break;
// I tried yielding an empty stream instead of break, again another hang!
// yield* Stream<userInfo>.empty();
} else {
// previous stream is dead, so create it again!
snapshots = Firestore.instance.collection(usersCollectionPath ).snapshots();
await for (QuerySnapshot snap in snapshots) {
for (DocumentSnapshot userDoc in snap.documents) {
yield (new userInfo.fromQuerySnapshot(userDoc));
}
}
});
}
Now even a try-catch block cannot catch what's gone wrong, when the stream is empty!
try{
getCurrentUserInfos().last.then((userInfolastOne) {
print("last one: $lastOne.name");
});
// the following line (i.e. await ...) at least doesn't hang and
// `catch` block is able to catch the error `Bad state: No element`,
// when the stream is empty
//
// userInfo lastOne = await stream.last;
} catch (ex) {
print ("ex: $ex");
}
There is no API to detect if a collection exists. In fact: a collection in Firestore only exists if there are documents in it.
The cheapest check I can think of is doing a query for a single document, and then checking if that query has any results.
Okay, maybe I figured it out
final snapshot = await Firestore.instance.collection(collectionName).getDocuments();
if (snapshot.documents.length == 0) {
//Doesn't exist
}
This worked for me
As stated by #Frank, a collection in Firestore gets deleted if no Documents exist in it.
However, I understand that there might be cases where you want to keep a history of the collection modification/ creation events, or let's say for some reason prevent Collections from being deleted.
Or for example, you want to know when a collection was created in the first place. Normally, if the Documents are deleted, and then the Collection gets created again, you will not know the initial creation date.
A workaround I can think of is the following:
Initialize each collection you want with a Document that will be specifically for keeping generic info about that collection.
For example:
This way, even if all other Documents in the Collection are deleted, you'll still keep the Collection in addition to some info that might be handy if In the future you need to get some history info about the Collection.
So to know if a Collection exists of no, you can run a query that checks for a field in Info Documents (eg CollectionInfo.exists) to know which Collections have been already created.
This is a sample from one of my projects. You can use snapshot.data!.docs.isEmpty to check if a collection has data or not.
StreamBuilder(
stream: _billGroupStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return const Center(
child: Text('Something went wrong'),
);
} else if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: Column(
children: const [
LinearProgressIndicator(),
Text('Loading data, please wait...'),
],
),
);
} else if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
} else if (snapshot.data!.docs.isEmpty) {
return const Center(
child: Text(
'Huh!! Looks like you have no transactions yet!' ,
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18),
),
);
} else if (snapshot.connectionState == ConnectionState.active) {
final List<DocumentSnapshot> docs = snapshot.data!.docs;
return ListView.builder(
shrinkWrap: true,
restorationId: 'billModeList',
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
///This document snapshot is used for determining the unique id for update and delete methods
final DocumentSnapshot doc = docs[index];
//final DocumentSnapshot doc = snapshot.data!.docs[index];
///This [BillModel] converted data is used to build widgets
final BillModel billModel = doc.data()! as BillModel;
return Dismissible(
onDismissed: (direction) {
_remoteStorageService.deleteItemFromGroup(
widget.uri, doc.id);
setState(() {
docs.removeAt(index);
});
},
background: Container(
color: Colors.red,
child: const Icon(Icons.delete_forever_sharp),
),
key: Key(doc.id),
child: Card(
elevation: 3,
shadowColor: Colors.teal.withOpacity(.5),
child: ListTile(
leading:
const CircleAvatar(child: Icon(Icons.attach_money)),
title: Text(billModel.name),
subtitle: Text(billModel.category ?? ''),
trailing: Text(billModel.amount.toString()),
),
),
);
},
);
}
return const CircularProgressIndicator();
},
),

Resources