Using .isGreaterThanOrEqual in .where method doesn't correctly sort Firebase Firestore documents in Flutter - database

I am trying to create simple Firebase Firestore query that allows the user to view the top forums from the previous day at most. This is the query I am currently using inside a ```StreamBuilder``` in Flutter.
_stream = FirebaseFirestore
.instance
.collection('forums')
.where(
'forumTimestamp',
isGreaterThanOrEqualTo: DateTime
.now()
.subtract(
const Duration(
days: 1),
)
.millisecondsSinceEpoch,
)
.orderBy(
'forumTotalLikes',
descending: true,
)
.snapshots();
This should return documents in my Firebase collection that were posted not more than a day ago, and then order them by the number of "forumTotalLikes," it has, to show the top posts from not more than a day ago. For context, this code changes a Streambuilder's stream when a user presses on a button, similar to reddit. When the user presses the button, and changes _stream to the above code, I get this error.
════════ Exception caught by gesture ═══════════════════════════════════════════
The following assertion was thrown while handling a gesture:
The initial orderBy() field "[[FieldPath([forumTotalLikes]), true]][0][0]" has to be the same as the where() field parameter "FieldPath([forumTimestamp])" when an inequality operator is invoked.
'package:cloud_firestore/src/query.dart':
query.dart:1
Failed assertion: line 485 pos 13: 'conditionField == orders[0][0]'
When I add
.orderBy('forumTimestamp')
Right of the comparision query, it loads, but doesn't correctly sort.
_stream = FirebaseFirestore
.instance
.collection('forums')
.where(
'forumTimestamp',
isGreaterThanOrEqualTo:
DateTime.now()
.subtract(
const Duration(
days: 1),
)
.millisecondsSinceEpoch,
)
.orderBy('forumTimestamp')
.orderBy(
'forumTotalLikes',
descending: true,
)
It only sorts forumTimestamp, but ignores the forumTotalLikes field. Note that there are no trivial mistakes, such as comparing invalid types. Whenever I remove the .where query entirely, it does correctly sort by the most liked forums. I just wan't to be able to get documents posted from not more than a day ago, and sort them by forumTotalLikes
Here for reassurance:

Related

save and query data from firestore with timeStamp or firebase server time in flutter

Please I have a history page on my flutter app that I want to work on and I have been thinking of a way to store the data correctly in my firestore so that I can achieve the desired result as seen in the picture below
I would love to have data of thesame day stored in thesame container as seen in the picture above. My challenge is, I do not know how to structure my data to get the desired result.
here is what I have tried;
my Count class file is below although I am not sure if that's what I will really do.
class Count {
String id;
final int count;
final createdOn;
Count({this.id = '', required this.count, required this.createdOn});
Map<String, dynamic> toJson() =>
{'id': id, "count": count, "createdOn": createdOn};
Count.fromSnapShot(DocumentSnapshot<Map<String, dynamic>> snapshot)
: id = snapshot.id,
count = snapshot.data()!["count"],
createdOn = snapshot.data()!["createdOn"];
}
and this is where I send data to firestore using onpressed in button
onPressed: () async {
exerciseCounter.increment();
final counter = exerciseCounter.count;
final FirebaseAuth auth = FirebaseAuth.instance;
final User? user = await auth.currentUser;
final uid = user?.uid;
final percents = FirebaseFirestore.instance
.collection('exercise-percentage')
.doc(uid)
.collection("daily-percentage");
final percent = Count(
count: counter,
createdOn: FieldValue.serverTimestamp());
final json = percent.toJson();
await percents.add(json);
},
now I am not sure of the correct way to use streambuilder to get the data from firestore and join the data of thesame day in thesame container. I understand that I will need to use query method to query my data with the firestore serverTimeStamp but I don't know how to use it to fetch data of thesame day and display it as shown in the picture above.
I will appreciate it if someone can really help me out. It can just be with a simple example I can follow or by correcting and adding to my code. Thank you for your time.
I would love to have data of the same day stored in the same container
as seen in the picture above.
You could have an extra field beside the createdOn one which holds the date in the following format YYYYMMDD.
This way, you can easily:
Query the Firestore document for a specific day
Use a set of count aggregation queries to calculate the KPIs/Counters for a specific day

SwiftUI FireStore - Get Field from Document and display as Text()

I'm very new to SwiftUI so bare with me - it's for a project.
I have stored user's details into my Firestore database which looks like this:
image of database
I want to take the name from the database and display it in a Text("Hello" [name])
I have been able to fetch the name from the database and append it into an array. This function is run when the 'Log in' button is clicked.
The code is as follows:
func getData(){
let docRef = db.collection(FStore.collectionName).document(userID)
docRef.getDocument { (document, error) in
if let document = document, document.exists {
if let fetchedName = document.get("name") as? String {
userArray.append(fetchedName)
print(userArray)
}
}
}
}
When printing userArray, the correct name does print.
However I am struggling to display the name outside of the console and on my Text UI field. When I attempt the code below, it gives me an index out of range error.
Text("Hello: \(userArray[0])")
Any help is appreciated / any other methods of retrieving field data from a specific document.
Thanks to #Steve M , it ended up being a kind of silly mistake.
He was right, the display was attempting to read the array before the array had even been populated.
As described in my comments, I called the getData() function then ran code to display the next screen. I wrapped the "display next screen code" in a DispatchQueue to delay the next screen being displayed
DispatchQueue.main.asyncAfter(deadline# .now() + 1){
nextView = true
}
This ran a 1-second delay before displaying the next screen and successfully displayed the name from the database.

Get Firestore collection and sub-collection document data together

I have the following Firestore database structure in my Ionic 5 app.
Book(collection)
{bookID}(document with book fields)
Like (sub-collection)
{userID} (document name as user ID with fields)
Book collection has documentes and each document has a Like sub-collection. The document names of Like collection are user IDs who liked the book.
I am trying to do a query to get the latest books and at the same time trying to get the document from Like sub-collection to check if I have liked it.
async getBook(coll) {
snap = await this.afs.collection('Book').ref
.orderBy('createdDate', "desc")
.limit(10).get();
snap.docs.map(x => {
const data = x.data();
coll.push({
key: x.id,
data: data.data(),
like: this.getMyReaction(x.id)
});
}
async getMyReaction(key) {
const res = await this.afs.doc('Book/myUserID').ref.get();
if(res.exists) {
return res.data();
} else {
return 'notFound';
}
}
What I am doing here is calling the method getMyReaction() with each book ID and storing the promise in the like field. Later, I am reading the like value with async pipe in the HTML. This code is working perfectly but there is a little delay to get the like value as the promise is taking time to get resolved. Is there a solution to get sub-collection value at the same time I am getting the collection value?
Is there a solution to get sub-collection value at the same time I am getting the collection value?
Not without restructuring your data. Firestore queries can only consider documents in a single collection. The only exception to that is collection group queries, which lets you consider documents among all collections with the exact same name. What you're doing right now to "join" these two collections is probably about as effective as you'll get.
The only way you can turn this into a single query is by having another collection with the data pre-merged from the other two collections. This is actually kind of common on nosql databases, and is referred to as denormalization. But it's entirely up to you to decide if that's right for your use case.

How to check for a specific date in an array

I'm trying to do some error handling on an existing system. The backend can't be changed as it runs multiple systems. I'm working on moving the frontend from ASP.NET to React. I've come across a problem where I want to check if an array of objects contains a date, but the date retrieved from the backend comes as a /Date(1379282400000)/.
I've done some searches and can't find something that resembles this.
I tried this code:
if (data.some(e => new Date(parseInt(e.Date.substr(6))).toDateString() === this.state.date.toDateString()) {
// Logic
}
e.Date is the key used in the object for the dates and this.state.date is a date picked by the user. If I just do:
if (data.some(e => e.Date === "/Date(137982400000)/") {
// Logic
}
as a test, then it works fine. So, it seems to be the converting of the date to the string that breaks the function, but can't understand how to fix it.
It would be nice to fix that it checks the date as doing .getTime() will not work as it could be the same date, but different times.
So, found out that the problem came from trying to convert the DateTime from the backend inside the .some() function, but I was able to work it out.
First I create a new array containing only the date as that was what I needed to run a check against:
const dateConvertion = data.map(function(elem) {
return {
date: new Date(parseInt(elem.Date.substr(6))).toDateString()
};
});
Then I created the error handling:
if (dateConvertion.some(e => e.date === this.state.date) {
// Error Handling
}

Creating a Multi-Contact Event with Apex in Salesforce

I am attempting to use Apex to create a multi-contact event.
I have already enabled Allow Users to Relate Multiple Contacts to Tasks and Events in the activity settings in the scratch org.
I am following the guide and the example at the bottom of these docs but I am constantly getting an error when pushing to the scratch org:
// ...
event.setEventWhoIds(attendeeContactIds);
// ...
Method does not exist or incorrect signature: void setEventWhoIds(List<String>) from the type Event.
I also tried to write directly to the field with:
event.EventWhoIds = attendeeContactIds;
With that, I get the error, that the field is not writable.
attendeeContactIds is a List of Strings representing Contact IDs.
What could I be missing? 🤔🙇🏻‍♂️
It's bit stupid, it's readonly in apex. It's exposed so integrations can quickly create event and essentially a related list together in one all-or-nothing transaction. See also https://salesforce.stackexchange.com/questions/238094/eventwhoids-is-not-writeable-in-apex-class-but-working-on-jsforce
Try something like that?
Savepoint sp = Database.setSavepoint();
event e = new Event(
StartDateTime = System.now(),
EndDateTime = System.now().addHours(1)
);
insert e;
List<EventRelation> invitations = new List<EventRelation>();
for(Contact c : [SELECT Id FROM Contact LIMIT 5]){
invitations.add(new EventRelation(
EventId = e.Id,
RelationId = c.Id,
IsInvitee = true
));
}
insert invitations;
Database.rollback(sp); // unless you really want to send it out

Resources