Flutter-Firebase read from firestore multiple fields including array - firebase

Im trying to read all the fields inside my uid1 and uid2 document from firestore. My code crashes because fromJson cant convert imageList from array to List.
Future<List<AppClient>> getClientListResult(List<String> listId) async{
final List<AppClient> clientList = <AppClient>[];
print(listId);
final QuerySnapshot<Map<String, dynamic>> snapshot = await _firestore.collection('clients').where('uid', arrayContainsAny: listId).get();
final List<AppClient> result = snapshot.docs.map((QueryDocumentSnapshot<Map<String, dynamic>> doc) => AppClient.fromJson(doc.data())).toList();
clientList.addAll(result);
return clientList;
}

you can use rxdart to combine two collection from firestore use this plugin rxdart
sample code
StreamBuilder(
stream: CombineLatestStream.list([
firestore
.collection('users')
.doc(data['id'])
.snapshots(),
firestore
.collection('Image')
.doc(data['id'])
.collection('Photos')
.orderBy('timestap')
.snapshots(),
]),
builder: (context, snapshotid) {
// here for the 1st stream
final active = snapshotid.data[0].data();
// here is the for the second stream
final active1 =
snapshotid.data[1].docs[0].data();

Your AppClient class should look something similar to this:
class AppClient {
String address;
String email;
List<String> imageList;
String name;
String price;
double rating;
List<String> uid;
AppClient(
{this.address,
this.email,
this.imageList,
this.name,
this.price,
this.rating,
this.uid});
AppClient.fromJson(Map<String, dynamic> json) {
address = json['address'];
email = json['email'];
imageList = json['imageList'].cast<String>();
name = json['name'];
price = json['price'];
rating = json['rating'];
uid = json['uid'].cast<String>();
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['address'] = this.address;
data['email'] = this.email;
data['imageList'] = this.imageList;
data['name'] = this.name;
data['price'] = this.price;
data['rating'] = this.rating;
data['uid'] = this.uid;
return data;
}
}

Related

How to retrieve the length of a map whose values are true only?

I would like to retrieve the length of a map in firebase whose values are true only. I have retrieved a document snapshot and currently have
Text(post['upvotes'].length.toString(), style: TextStyle(color: Colors.grey[100])
How do i get those whose values are true only?
class Post { //for forums
String title;
String content;
String timestamp;
String imageurl;
String username;
String profilePicture;
String documentid;
String ownerid;
Map<String, dynamic> saved = {};
Map<String, dynamic> upvotes = {};
Post(
this.title,
this.content,
this.timestamp,
this.imageurl,
this.username,
this.profilePicture,
this.documentid,
this.ownerid,
this.saved,
this.upvotes
//this.image
);
Post.fromSnapshot(DocumentSnapshot snapshot) :
title = snapshot["title"],
content = snapshot['content'],
timestamp = snapshot['timestamp'],
imageurl = snapshot['imageurl'],
username = snapshot['username'],
profilePicture = snapshot['profilePicture'],
documentid = snapshot['documentid'],
upvotes = snapshot['upvotes'],
ownerid = snapshot['ownerid'],
saved = snapshot['saved'];
}

how to display a custom list data on the app page in flutter

1[https://i.stack.imgur.com/yI2Cp.png">]1
i have tried this code to retrieve data from subcollection of the same name(userProducts) stored in many firebase documents.How do i display this data in a container on the app page ? I tried using listiew.builder but it doesnt work.
The first function
static List<products> finalProductsList = [] ;
productsList() async
{
List list_of_products = await Firestore.instance.collection("products")
.getDocuments()
.then((val) => val.documents);
for (int i=0; i<list_of_products.length; i++)
{
Firestore.instance.collection("products").document(
list_of_products[i].documentID.toString()).collection("userProducts").snapshots().listen(CreateListofProducts);
}
}
Second function
CreateListofProducts(QuerySnapshot snapshot)async
{
var docs = snapshot.documents;
for (var Doc in docs)
{
finalProductsList.add(products.fromFireStore(Doc));
}
}
CourseModel
class products {
final String prodId;
final String ownerId;
final String username;
final String price;
final String productname;
final String details;
final String color;
final String composition;
final String washandcare;
final String sizeandfit;
final String shopmediaUrl;
final String id;
final dynamic likes;
products({ this.prodId,
this.ownerId,
this.username,
this.price,
this.details,
this.productname,
this.color,
this.composition,
this.washandcare,
this.sizeandfit,
this.shopmediaUrl,
this.id,
this.likes,});
factory products.fromFireStore(DocumentSnapshot doc)
{
Map data = doc.data ;
return products(
prodId: doc['prodId'],
ownerId: doc['ownerId'],
username: doc['username'],
price: doc['price'],
productname: doc['productname'],
details: doc['details'],
shopmediaUrl: doc['shopmediaUrl'],
color:doc['color'],
composition:doc['composition'],
washandcare:doc['washandcare'],
sizeandfit:doc['sizeandfit'],
likes: doc['likes'],
);
SO if i understand you, you want to get data on multiple collections on multiple documents?
If so... you should use collecionGroup, you can learn how to use here, make sure to adjust your firestore rules.

How do i get a DocumentSnapshot of a map and retrieve the length of the map?

I would like to get the length of Map<String, bool> upvotes as shown in the picture of firebase and display the number of upvotes for a post. How do i get the documentSnapshot of the field in the first place? I have a snippet of the code as shown but there is an error.
class Post { //for forums
String title;
String content;
String timestamp;
String imageurl;
String username;
String profilePicture;
String documentid;
String ownerid;
Map<String, bool> saved = {};
Map<String, bool> upvotes = {};
//Map<String, bool> saved;
Post(
this.title,
this.content,
this.timestamp,
this.imageurl,
this.username,
this.profilePicture,
this.documentid,
this.ownerid,
this.saved,
this.upvotes
//this.image
);
Post.fromSnapshot(DocumentSnapshot snapshot) :
title = snapshot["title"],
content = snapshot['content'],
timestamp = snapshot['timestamp'],
imageurl = snapshot['imageurl'],
username = snapshot['username'],
profilePicture = snapshot['profilePicture'],
documentid = snapshot['documentid'],
upvotes = snapshot['upvotes'], //gives error as shown in red image
ownerid = snapshot['ownerid'],
saved = snapshot['saved'];//gives error as shown in red image
}

How to convert a sub collection to list with flutter and firestore?

I have an object Dish who containes a list of ingredients and I want to get them. How can I do?
In Firebase, Dish is a Document and Ingredient is a sub collection. I tried this but it doesn't work.
class Dish{
String name;
DocumentReference reference;
List<Ingredient> ingredients;
Dish.fromMap(Map<String, dynamic> map, {this.reference}){
this.name = map['name'];
this
.reference
.collection("ingredients")
.snapshots()
.listen((QuerySnapshot snap) {
final List<DocumentSnapshot> ingredientsDocuments = snap.documents;
List<Ingredient> ing = [];
for (var i = 0; i < ingredientsDocuments.length; i++) {
ing.add(Ingredient.fromSnapshot(ingredientsDocuments[i]));
}
this.ingredients = ing;
});
}
Dish.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data, reference: snapshot.reference);
#override
String toString() => "Dish<$String>";
}
class Ingredient{
final String name;
final DocumentReference reference;
Ingredient.fromMap(Map<String, dynamic> map, {this.reference})
: assert(map['name'] != null),
name = map['name'];
Ingredient.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data, reference: snapshot.reference);
#override
String toString() => "Ingredient<$String>";
}
How are you trying to fetch data from Firestore using Dish class? Were you using any asynchronous task(i.e. Future)? What's not working in your implementation? Any errors that you received?
Since I'm unable to run the repro you've provided, here's a sample code that you can try.
List<Ingredient> ingredients;
// call getDocuments() to fetch data from Firestore and add it to the List
Future<void> getDocuments() async {
ingredients = List();
var collection = FirebaseFirestore.instance
.collection('ingredients');
collection.get().then((value) {
value.docs.forEach((element) {
setState(() {
// add the object to the List
ingredients.add(Ingredient(Ingredient.fromMap(element.data())));
});
});
});
}
As for the Object, it can be as simple as this. No need to pass DocumentReference since we'll only be using it to map the data to the Object and be able to add it in the List.
class Ingredients {
var name;
Ingredients(Ingredients document) {
this.documentName = document.getName();
}
dynamic getName() => name;
Ingredients.fromMap(Map<dynamic, dynamic> document)
: name = document['name'];
}
You can check a working sample I've posted in here. It has pagination added, but it should have a similar approach with the code snippets I've shared here.

Returning values in async functions - Flutter

Using Cloud Firestore as my DB.
I need to read data from two separate documents in my code, get data from a document based on value in the previous document.
Getting data from firestore in a Future method which looks like this:
Future<List<Map<String, dynamic>>> getGenAlertsData() async{
QuerySnapshot alertRef = await Firestore.instance.collection('alerts').orderBy('time', descending: true).getDocuments();
List<Map<String, dynamic>> messages = new List();
Map<String, dynamic> fullMessage;
// int counter = 0;
alertRef.documents.forEach((doc) async {
// counter++;
String senderKey, senderNameKey, senderSpecKey, senderPicKey, msgBodyKey, timeKey, sender, senderName, senderSpec, msgBody, senderPic;
senderKey = 'sender';
sender = doc['sender'];
timeKey = 'time';
DateTime time = doc['time'];
print(time);
msgBodyKey = 'msgBody';
msgBody = doc['msgBody'];
DocumentReference ref = Firestore.instance.document('/staff/'+sender);
print(ref.documentID);
await ref.get().then((onValue) { //values not populated here :(
senderNameKey = 'senderName';
senderName = onValue['name'];
print(senderName);
senderPicKey = 'senderPic';
senderPic = onValue['profilePic'];
senderSpecKey = 'specialization';
senderSpec = onValue['specialization'];
});
// await print(senderName);
fullMessage = <String, dynamic> {
senderKey: sender,
senderNameKey: senderName,
senderSpecKey: senderSpec,
senderPicKey: senderPic,
timeKey: time,
msgBodyKey: msgBody,
};
messages.add(fullMessage);
print(messages.toString()); // I get the messages printed in my console here
}); //loop over collection ends here
print(messages.toString()); // No data here :(
return messages;
}
At this point only the values from alertRef.documents.forEach((doc) are avaialble, and the values inside await ref.get().then((onValue) { are not populated (they are null in the fullMessage Map) .
Any help will be greatly appreciated.
Yaay! Figured it out finally!
Apparently, then() doesn't work that well inside async functions, now my code looks like this, and everything's great now! :)
Put it all in a good old for loop and everything''s fine now.
Future<List<Map<String, dynamic>>> getGenAlertsData() async{
QuerySnapshot alertRef = await Firestore.instance.collection('alerts').orderBy('time', descending: true).getDocuments();
List<Map<String, dynamic>> messages = new List();
Map<String, dynamic> fullMessage;
// String xxx;
String senderKey, senderNameKey, senderSpecKey, senderPicKey, msgBodyKey, timeKey, sender, senderName, senderSpec, msgBody, senderPic;
List<DocumentSnapshot> alertSnaps= alertRef.documents;
for (int i = 0; i < alertSnaps.length; i++)
{
senderKey = 'sender';
sender = alertSnaps[i]['sender'];
timeKey = 'time';
DateTime time = alertSnaps[i]['time'];
print(time);
msgBodyKey = 'msgBody';
msgBody = alertSnaps[i]['msgBody'];
DocumentSnapshot snappy = await Firestore.instance.document('/staff/'+sender).get();
senderNameKey = 'senderName';
senderName = snappy['name'];
print('Doc for sender' + senderName);
senderPicKey = 'senderPic';
senderPic = snappy['profilePic'];
senderSpecKey = 'specialization';
senderSpec = snappy['specialization'];
fullMessage = <String, dynamic> {
senderKey: sender,
senderNameKey: senderName,
senderSpecKey: senderSpec,
senderPicKey: senderPic,
timeKey: time,
msgBodyKey: msgBody,};
messages.add(fullMessage);
}
return messages;
}

Resources