Retrieving null object from Firestore when its not actually null - android

I've been trying to understand why my query returns null object from server generated timestamp value.
Basically, I used onUpdate() trigger on my Firestore database and check, if the product is low on stock and make a reminder when the stock is <=5. This is my Node.js code and it currently works even tho it's got no proper responses.
const date = admin.firestore.FieldValue.serverTimestamp();
const reminder = {
productID : product.barcode,
date : date,
status: 'Order'
}
const docSnapShot = admin.firestore().collection('reminders').doc(product.barcode).get().then(documentSnapShot =>{
if(documentSnapShot.exists){
return admin.firestore().collection('reminders').doc(product.barcode).update({date: date}).then(res=> {
console.log('Document updated');
return null;
}).catch(error =>{
console.log('Error',error);
return null;
});
}
else{
exists = docSnapShot.exists;
return null;
}
});
Server successfully inserts the generated timestamp and even when manually added, It still retrieves a null object in Java/Android. Using FirestoreRecyclerView and an RecyclerView custom adapter and class. I tried ServerTimeStamp and double checked variable names, sequence and I still get a null object. I get proper productID and status values.
public reminderFirestore(Timestamp date, String productID, String status) {
this.productID = productID;
this.date = date;
this.status = status;
}
Has this something to do with my constructor and object type or did I mess up in the server/Node.js code?

You need to include the default empty constructor and getters for all fields. If only your timestamp is null, then you must not have a getter for timestamp.

Related

How to sort a list in Flutter

I am building a list in flutter and need to sort it by date by showing the most recent timestamp first.
The list is created from a json like the one below:
[
{
"id":100,
"timestamp":"2021-02-02T15:15:11Z",
"name":"Entry1"
},
{
"id":101,
"timestamp":"2021-03-02T11:12:56Z",
"name":"Entry2"
}
]
Once the json is fetched with the fetchEntries function, I'd like to sort the list. This is my code:
class Values extends Object {
int id;
String timestamp;
String name;
Values(
{this.id,
this.timestamp,
this.name});
Values.fromJson(Map<String, dynamic> json) {
id = json["id"];
timestamp = json["timestamp"];
name = json["name"];
}
}
List<Values> _myList = [];
fetchReport() {
_timer = new Timer.periodic(Duration(seconds: 1), (timer) {
fetchEntries(dates.id.toString(), dates.from, dates.to)
.then((value) => {
_myList.addAll(value),
_postsController.add(1),
setState(() {})
});
_timer.cancel();
});
//This is the sort code that doesn't work
_myList.sort((a,b)=> a.timestamp.compareTo(b.timestamp));
}
Alternatively, the list can be sorted by id in decreasing order but the timestamp method is preferred. Any suggestions how to do it properly?
It is better to parse time after fetch data.
_myList.sort((a,b) {
DateFormat formatter = DateFormat("yyyy-MM-ddTHH:mm:ssZ");
DateTime aTime = formatter.parse(a["timestamp"]);
DateTime bTime = formatter.parse(b["timestamp"]);
return aTime.compareTo(bTime);
//return bTime.compareTo(aTime);
}
I think that issue why sorting does not work is that _myList.sort function is called before _myList is filled with data. The reason of that is that _myList is populated in future (when callback of fetchEntires(...).then) is called, while sort function is called right after timer is created (after Timer.periodic constructor).
In order to fix that you need to move _myList.sort to callback just after list is populated with data.
Regarding sorting itself.. While it should work comparing date in the format of your example, I would rather parse time to milliseconds and then compare those instead. Reason is that once you change date format to different one, like 'dd-MM-yyyy' sorting will be broken.

Saving TimeStamp as a negative value using ServerValue.TIMESTAMP in FireBase Database

I want to save the data in firebase database with a descending order and I found that the solution is to add a timeStamp field with a negative value, but using ServerValue.TIMESTAMP save only the value in a positive way,so how can I save a negative timeStamp in my FireBase :
Code of model:
public class Book{
Object createdTimestamp;
String nom_livre;
String desc_livre;
String prix_livre;
String id_book;
String id_user;
public Book() {
super();
}
public Book(String nom_livre, String desc_livre, String prix_livre, String id_book,String id_user, Object createdTimestamp) {
super();
this.nom_livre = nom_livre;
this.desc_livre = desc_livre;
this.prix_livre = prix_livre;
this.id_book = id_book;
this.id_user=id_user;
this.createdTimestamp= createdTimestamp;
}
#Exclude
public long getCreatedTimestampLong(){
return (long)createdTimestamp;
}
//other getters and setters
}
Code of adding data in fireBase , im my case I'm creating a Book on addBookActivity:
private void createBook(String nom_livre, String desc_livre,String prix_livre,Object createdTimestamp) {
bookInfos=new Book(nom_livre,desc_livre,prix_livre,idLivre,id, ServerValue.TIMESTAMP );
myRefBook.child(idBook).setValue(bookInfos);
}
You have two options, and they both require a second write to the database after you initially write the regular timestamp number as a positive number.
If you only want to write data on the client app, what you can do is write your createdTimestamp as you are right now, then read that value back into the client by listening to the location that you just wrote. After you read it back in, you'll have the actual timestamp value. Then, you can easily compute the negative it and write it back where you want it (maybe revCreatedTimestamp, if you're using it to sort in reverse chronological order).
Your other option is to use Cloud Functions for Firebase to write a Realtime Database trigger to respond to writes that match the location /books/{book_id} where book_id is that string you're generating for the book. That trigger can then capture the timestamp and write back the negative version at the same location.

Realm Update Table Ignore Field

Following is Pojo are extended by realm , at first time getting all fields from api and i am using insertOrUpdate() operation of realm to dump data in realm.
ServiceModel.java
#JsonProperty("id")
private String id;
#JsonProperty("title")
private String title;
#JsonProperty("description")
private String description;
#JsonProperty("current_status")
private String currentStatus;
But for next time i am not getting current_status field from response and so my ServiceModel table is getting updated with currentStatus as null. How To make currentStatus to not getting updated if it is not in response.
I had the same problem and here how I solved it. You should select existing Object by id:
ServiceModel existingService = realm.where(ServiceModel.class).equalsTo("id",id).findFirst();
if(existingService !=null){ // check if such record existed, it may be absent
String oldCurrentStatus = existingService.currentStatus();
//set old current status to new API object
}
I had the same problem and as far as I know there is no Realm function or annotation yet for such case.

Overriding toString to return more than one variable

I have a Story class with the following variables, which correspondent to database columns:
int id;
String title;
int author_id;
String collection;
String body;
I have overridden toString() to return title like so:
#Override
public String toString() {
return title;
}
With this setup, I can successfully pull all story titles from my database.
But what if I also want to pull all story collections? Is it possible to return more than one variable in the override, or should I look at another approach?
The toString generates a String representation of your object as a human readable text, you can concatenate the result of many vars AS a String
return title + " " + collection;
Java does not support multiple returns out of the box. I think your best options would be to either:
Encapsulate the data that you want to return into a simple Java class, so you can set the fields and return it as one object.
In a function that returns your object, when you are getting ready to return:
MyReturnObject obj = new MyReturnObject();
obj.setTitle(title);
obj.setCollection(collection);
return obj;
Alternatively you can return the collections with some sort of delimiter, so that you can extract the data you want later on: return title + "|" + collections;
This will leave you with a String like: myTitle|collection1|collection2|collection3, which you can parse by String[] tokens = myString.split("|");

Marshalling Undetermined data type

With a custom Marshaller I try to map a DynamoDB query to an object
class ownObject {
private int myInteger;
#DynamoDBMarshalling(marshallerClass = MasrshallAsInteger.class)
#DynamoDBAttribute
public int getMyInteger {
return myInteger;
}
public void setMyInteger(int newint) {
myInteger = newint;
}
}
Since the value myInteger in the db has both types String and Number, the SDK throws the Exception: "Expected S in value {N:123,}" if I use the marshaller and "Expected N in value {S:123,}" on an other object if I don't .
Is there any way to force the DynamoDB to use a custom marshaller and parse the value of the Key as String? Or is there any other way to parse a undetermined type of data but using PaginatedQueryList?
I recommend you use the Document SDK to paginate, parse your items into Item objects, paginate, and then convert those Items to your domain.
Table table = new AmazonDynamoDBClient(new DefaultCredentialsProviderChain()).getTable("ownObject");
for (Item item : table.scan()) {
//convert item to your domain object here
}

Categories

Resources