Firestore compound query not working for Flutter Web - flutter

Hi I have a simple query for Firestore in a StreamBuilder
StreamBuilder(
stream: FirestoreManager.firebaseFirestore
.collection("orders")
.orderBy('logs.0', descending: true)
.where('status', whereIn: current['id'])
.snapshots(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snap) {
print(snap.data.toString());
if (!snap.hasError && snap.hasData) {
QuerySnapshot snapshot = snap.data;
if (snapshot.documents.isNotEmpty) {
List<DocumentSnapshot> snapList = snapshot.documents;
return ListView.builder(
padding: EdgeInsets.only(right: 10, left: 10),
physics: ScrollPhysics(),
itemCount: snapList.length,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return OrderListItem(
order: Order.fromJson(snapList[index].data),
);
},
);
} else {
return Center(
child: Text(
"No ${current['status'].toString().trim()} Order Available...!",
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
);
}
} else {
return Center(
child: CircularProgressIndicator(),
);
}
})
It works absolutely fine for mobile appilcaiton but when I try to run it for web, It doesn't work.
Actually it shows data once for a second and again disappears. I got following log in console by printing snapshot data using print(snap.data.toString());
js_primitives.dart:30 null
js_primitives.dart:30 Instance of 'QuerySnapshot'
js_primitives.dart:30 null
Why is this happening? Why it shows data once and again disappear it?
If I remove either .orderBy('logs.0', descending: true) or .where('status', whereIn: current['id']) then it works fine.

I am having the same problem with flutter web. I am trying to use two chained where() methods and it doesn't give me any results:
StreamBuilder(
stream: fire
.collection('thiHistory')
.where("device", "==", _device)
.where("ts", '>=', ts)
.onSnapshot,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) return Text('Loading....');
final docs = snapshot.data.docs;
return ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: docs.length,
itemBuilder: (context, index) {
final doc = docs[index].data();
return doc["device"] == _device ? Column(
children: [
Text(doc['device']),
Text("${doc["hour"]}"),
Text("${doc["temp"]}"),
Text("${doc["humi"]}"),
Text("${doc["thi"]}"),
],
) : Container();
});
},
)
If I only use one where() or the other it works fine. If I use both, I always get "Loading....", which tells me the snapshot has no data.
I also tried chaining orderedBy() with where() like Shahzad Akram, and same thing... Using one or the other works great, combining them does not return data.
I am using the firebase 7.3.0 package and version 7.19.1 of the libraries:
<script src="https://www.gstatic.com/firebasejs/7.19.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.19.1/firebase-database.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.19.1/firebase-firestore.js"></script>
Thanks for your help.

Related

How to sort a length of int from a doccumentSnapshot in a listview.builder Flutter

I have already get the snapShot of array and count it using length. And displayed it. But I want to reorder it from much to lower in a listview.builder. How can I achieve that?
Backed structure
Code so far
//I forgot to mention
//This is the usersCommentId from the snapShot of StreamBuilder on top of the widget tree
final usersComment = snapshot.data?['usersComment'];
ListView.builder(
physics: const BouncingScrollPhysics(),
itemCount: usersComment.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection("usersComment")
//I tried filtered it here But that doesn’t work
.where(usersComment[index])
.snapshots(),
builder: (context,
AsyncSnapshot<
QuerySnapshot<
Map<String, dynamic>>>
snapshot) {
final userComments = snapshot.data!.docs
..sort((a, b) => ((b.data()['vote']
as List<dynamic>?)
?.length ??
0)
.compareTo((a.data()['vote']
as List<dynamic>?)
?.length ??
0));
final comment = userComments[index];
final countVote = (comment.data()['vote']
as List<dynamic>?)
?.length ??
0;
if (!snapshot.hasData) {
return Container();
}
return Text(
countVote.toString(),
style: const TextStyle(
color: Colors.black, fontSize: 15),
);
});
}),
As you have already taken all List of userComments, I have a suggestion to make it with in single Stream query as following
StreamBuilder(
stream: FirebaseFirestore.instance
.collection("usersComment").snapshots(),
builder: (context,
AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>>
snapshot) {
final userComments = snapshot.data!.docs..sort((a, b) => ((b.data()['vote'] as List<String>?)?.length ?? 0).compareTo((a.data()['vote'] as List<String>?)?.length?? 0));
ListView.builder(
itemCount: userComments.length,
itemBuilder: (context, index){
final comment = userComments[index];
final countVote = (comment.data()['vote'] as List<String>?)?.length ?? 0;
return Text(
countVote.toString(),
style: const TextStyle(
color: Colors.grey,
fontSize: 9),
);
});
});
If you want to filter the userComments, then stream: FirebaseFirestore.instance .collection("usersComment").where(%your condition%).snapshots()
take out the listview.
return listView inside the stream builder.
return everything in the collection (not each doc).
add all the votes in one list inside your stream builder.
sort the list and display using the ListView that is inside the stream
how to sort in dart
You can sort the usersComment array before passing it to the ListView.builder by using the sort method from the List class. You can sort the list by using a custom sorting function that compares the vote counts of each DocumentSnapshot in the list. Here is an example:
usersComment.sort((a, b) {
return FirebaseFirestore.instance
.collection("usersComment")
.doc(b)
.get()
.then((bSnapshot) {
final bVote = bSnapshot.data?['vote'];
final bCountVote = bVote?.length ?? 0;
return FirebaseFirestore.instance
.collection("usersComment")
.doc(a)
.get()
.then((aSnapshot) {
final aVote = aSnapshot.data?['vote'];
final aCountVote = aVote?.length ?? 0;
return bCountVote - aCountVote;
});
});
});

.where() not working with StreamBuilder steam | firestore query require an index - Flutter

I want to display groups with this condition
current user id must include in the members array of group collection
order by LastUpdate (time)
So, I used steam like this
StreamBuilder(
stream: FirebaseFirestore.instance
.collection("groups")
.orderBy('LastUpdate', descending: true)
.where(
"members",
isEqualTo: FirebaseAuth.instance.currentUser!.uid,
)
.snapshots(),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasError) {
return Text(
'${snapshot.error}',
style: const TextStyle(color: Colors.white),
);
}
if (snapshot.hasData) {
return Padding(
padding: const EdgeInsets.only(top: 5),
child: ListView.builder(
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
return Text(
snapshot.data.docs[index]['groupName'],
style: const TextStyle(fontSize: 40, color: Colors.white),
);
},
),
);
} else {
return const Center(
child: CircularProgressIndicator(color: Colors.white),
);
}
});
When I run first time, It showed error and said,
FAILED_PRECONDITION: The query requires an index. You can create it here: ...
I created it. there is picture of it,
With this, Application run without error. But,
When I use .where( "members",isEqualTo: FirebaseAuth.instance.currentUser!.uid,), It not display anything. empty without any error.
(There are 3 groups, this user id has in the member's array - its sure. I checked it correctly)
When I remove .where( "members",isEqualTo: FirebaseAuth.instance.currentUser!.uid,) from snapshot. It working properly.
What can I do to fix this. HELP
If members is an array in a document, you must use "arrayContains" not "isEqualTo"
.where(
"members",
arrayContains: FirebaseAuth.instance.currentUser!.uid,
)

Null check operator used on a null value FirebaseFirestore

I want to sort the posts in my application by date, but when I use orderby I get a null check operator used on a null value error. The problem is that when I type 'where' together with 'orderby' there is a problem.
My code below:
StreamBuilder(
stream: FirebaseFirestore.instance
.collection('posts')
.where('uid', isEqualTo: widget.uid)
.orderBy(
'datePublished',
descending: true,
)
.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
primary: false,
shrinkWrap: true,
itemCount: (snapshot.data! as dynamic).docs.length,
itemBuilder: (context, index) {
DocumentSnapshot snap =
(snapshot.data! as dynamic).docs[index];
Firestore is an optimized database. As a result, you have to create composite indexes for complex queries, like the one you are doing (combining orderBy with where), to work.
To solve this problem, look at the logs where you are running Flutter. you should see a Firebase Console link that will take you straight to creating the query. Create the query, wait for 5 minutes or less for it to build, then try the code again. It should work.
because stream can be return null value then snapshot.data! as dynamic make error. Please check snapshot.hasData
Add 1 more condition
if (snapshot.data == null) {
return const Center(
child: CircularProgressIndicator(),
);
}

How to get the Different User Story's like Instagram and any other Social media app

here is my database first Image
2nd Image
finlal Image
whenever user uploads story the "stroyAdded" feild gets true thats how Iam fetching the list of the user who have uploaded the story
here is the code of the particular
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("users")
.where("stroyAdded", isEqualTo: true)
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.connectionState ==
ConnectionState.active) {
return ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
var data =FirebaseFirestore.instance.
collection("users").doc(snapshot.data!.docs[index].
get("uid")).collection("Stories").snapshots();
print(snapshot.data!.docs.length);
return Padding(
padding: EdgeInsets.symmetric(
horizontal: 10),
child: StoryCircle(
() {
Navigator.push(context, MaterialPageRoute(builder: (context)=>StoryPage();
},
snapshot.data!.docs[index]
.get("profile"),
snapshot.data!.docs.length),
);
});
}
} else {
// No data
}
return const Center(
child: CircularProgressIndicator());
})
My desire output
I'm guessing that you only want to show the storys from the last 24h like other solical media plattforms. In this case the best way to query all the stories from the diffrent collections would be to us a singel query with a collection group query.
You can read more about it here: https://firebase.google.com/docs/firestore/query-data/queries#java_30
My solution:
db.collectionGroup("Stories").whereGreaterThan("time", yourDateObject - 24h)
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
// ...
}
});

Flutter List UI not updating properly

I am building a one to one chat app using Flutter and firebase and I want to display all the chats under label of the day on which it happened,like it is on all major chat apps.
I retrieve data from firestore in ascending order of time by using order by command on the timestamp field of each message and as suggested by NiklasLehnfeld
i used groupBy method in the collection package to group my messages and used nested list view builders outer one for creating groups and inner one for filling those groups with data.
Here is the code
Widget build(BuildContext context) {
return FutureBuilder(
future: FirebaseAuth.instance.currentUser(),
builder: (ctx, futureSnapshot) {
if (futureSnapshot.connectionState == ConnectionState.waiting) return Center(child: CupertinoActivityIndicator());
return StreamBuilder(
stream: Firestore.instance
.collection('mychats/${futureSnapshot.data.uid}/${widget.recieverUid}')
.orderBy('createdAt', descending: true)
.snapshots(),
builder: (context, chatSnapshots) {
if (chatSnapshots.connectionState == ConnectionState.waiting)
return Center(child: CupertinoActivityIndicator());
else {
final List chatDocs = chatSnapshots.data.documents;
Map<String, List> grouped = groupBy(chatDocs, (chat) {
String dateTime = chat['dateTime'];
return dateTime;
});
(grouped.forEach((m, v) {
print('$m');
for (int i = 0; i < v.length; i++) {
print(v[i]['text']);
}
}));
return ListView.builder(
reverse: true,
itemCount: grouped.keys.length,
itemBuilder: (ctx, index1) {
String date = grouped.keys.toList()[index1];
List messages = grouped[date];
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(date),
ListView.builder(
reverse: true,
primary: false,
shrinkWrap: true,
itemCount: messages.length,
itemBuilder: (context, index) {
return MyMessageBubble(
chatDocs[index].documentID,
chatDocs[index]['text'],
(chatDocs[index]['userId'] == futureSnapshot.data.uid) ? true : false,
ValueKey(chatDocs[index].documentID));
})
],
);
});
}
},
);
},
);
}
This is the list of messages that I am fetching
This is the UI .The results that i am printing in console are not displaying correctly in UI.I tried setting keys for both the list builders but no success. Is there any way it can be corrected
You are using the wrong list:
This:
chatDocs[index].documentID,
chatDocs[index]['text'],
(chatDocs[index]['userId'] == futureSnapshot.data.uid) ? true : false,
ValueKey(chatDocs[index].documentID));
should reference messages, not chatDocs. Because index is the index into messages.
the documentId is not work
chatDocs[index]['text'],
chatDocs[index]['userId'] == futureSnapshot.data.uid,
key: ValueKey(chatDocs[index].id),
just use only id