Reputation: 260
I'm creating an Android application wherein I have to keep count of YTD, MTD, and Daily record punched for an organization as well as individual users. I tried the approach where for every save of record, I have a counter collection where I save data like
ORG_ORGID_2020 (for YTD)
ORG_ORGID_202005 (for MTD)
ORG_ORGID_20200513 (for Daily data)
ORG_USER1_2020 (for YTD)
ORG_USER2_202005 (for MTD)
ORG_USER3_20200513 (for Daily data)
so that I don't have to read many documents while fetching reports. Now to minimize the reads I save properties in the above documents (org_ID, year (i.e. 2020), yearMonth (i.e.202005), and so on. I save above documents in the form of the counter object
public class Counter {
@DocumentId
private String id;
private long count;
private String dealerId;
private String userId;
private String year;
private String yearMonth;
private String yearMonthDate;
}
Not the issue arises when I have to update the counter. I tried using
private FieldValue count;
and was able to update the count properly using
Counter counter = new Counter();
counter.setCount(FieldValue.increment(1));
counter.setDealerId(intentDealer.getId());
counter.setYear(strFullYear);
batch.set(dealerYtdColRef, counter, SetOptions.merge());
but when I try to fetch the record, I get
java.lang.RuntimeException: No properties to serialize found on class com.google.firebase.firestore.FieldValue
if I change the field to
private long count;
I'm not getting as, how to update the counter. I have to set all fields too along with the counter. I tried using .update method too, but it gives an error when the document is not present and has to be created for the first time.
Hw can I properly manage the counters? I'm doing counter part from app-only instead of functions because I'm trying to get the app work in free firebase tier only.
Upvotes: 1
Views: 222
Reputation: 260
Finally, as per suggestion from Alex, I use the map values, but at the same time, I moved my code to google. Please let me know if I have done the implementation wrong. It seems to work though
const functions = require('firebase-functions');
// The Firebase Admin SDK to access the Firebase Realtime Database.
const admin = require('firebase-admin');
admin.initializeApp();
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
// exports.helloWorld = functions.https.onRequest((request, response) => {
// response.send("Hello from Firebase!");
// });
const db = admin.firestore();
// [START_EXCLUDE]
const settings = { timestampsInSnapshots: true };
db.settings(settings);
// [END_EXCLUDE]
// [START aggregate_function]
exports.aggregateEnquiries = functions.firestore
.document('enquiries/{id}')
.onWrite(async (change, context) => {
if (!change.before.exists) {
// New document Created : add one to count
var dealerId = change.after.data().dealerId;
var userId = change.after.data().assignedTo;
var date = change.after.data().createdDt.toDate();
var day = date.getDate();
var month = date.getMonth() + 1;
var year = date.getFullYear();
var yearMonth = String(year) + (month < 10 ? "0" + month : month);
var yearMonthDate = yearMonth + (day < 10 ? "0" + day : day);
try {
return await db.collection("dealers").doc(dealerId)
.get()
.then((doc) => {
if (doc !== null && doc.exists) {
const increment = admin.firestore.FieldValue.increment(1);
db.collection("enquiries_agg")
.doc("D_" + dealerId + "_" + year)
.set({ "count": increment }, { merge: true });
db.collection("enquiries_agg")
.doc("D_" + dealerId + "_" + monthYear)
.set({ "count": increment }, { merge: true });
db.collection("enquiries_agg")
.doc("U_" + userId + "_" + year)
.set({
"count": increment,
"dealerId": dealerId,
"userId": userId,
"reference": String(year)
}, { merge: true });
db.collection("enquiries_agg")
.doc("U_" + userId + "_" + yearMonth)
.set({
"count": increment,
"dealerId": dealerId,
"userId": userId,
"reference": String(yearMonth)
}, { merge: true });
db.collection("enquiries_agg")
.doc("U_" + userId + "_" + yearMonthDate)
.set({
"count": increment,
"dealerId": dealerId,
"userId": userId,
"reference": String(yearMonthDate)
}, { merge: true });
} else {
console.log("error in aggregare entries.");
}
return null;
});
}
catch (error) {
console.log("Error getting documents: ", error);
throw new Error("Profile doesn't exist : " + error);
}
} else if (change.before.exists && change.after.exists) {
// Updating existing document : Do nothing
} else if (!change.after.exists) {
// Deleting document : subtract one from count
}
return null;
});
Upvotes: 0
Reputation: 138814
The problem in your code is the following line of code:
counter.setCount(FieldValue.increment(1));
Your count
property is defined in your Counter
class to be of type long. When you are using the setCount()
method to set its value, you should pass a long value as an argument but you actually don't. The following statement:
FieldValue.increment(1)
Return an object of type FieldValue and not a long, hence that error. To increment the value of your count property atomically by one, please use the following lines of code:
Map<String, Object> updateCount = new HashMap<>();
updateCount.put("count", FieldValue.increment(1));
yourDocRef.set(updateCount, SetOptions.merge());
Upvotes: 1