(( SOLVED ))
Looking to get some help to figure out this weirdness, first up I'm new to JS & Firebase, so I might be missing the obvious here. In any case, I'm trying to turn the timestamp into a negative number, to order documents and always get the latest 10 if I limit them in a query call.
However, the code below throws an error when trying to run it in Cloud Functions.
IF I console.log the (-Math.abs(timestamp)) client-side however, I get a negative number just fine. Anyone here to help with this problem and/or provide a workaround?
// create welcome post on new user signup
exports.createWelcomePost = functions.auth.user().onCreate((user) => {
const uid = user.uid;
const userName = user.displayName;
const photoURL = user.photoURL;
const timestamp = admin.firestore.FieldValue.serverTimestamp();
const order = -Math.abs(timestamp);
const db = admin.firestore();
const docRef = db.collection('posts');
docRef.add({
order: order,
created: timestamp,
createdBy: uid,
userName: displayName,
userImage: photoURL,
content: "...just joined the Startly Community, let's give him a warm welcome!",
featuredImage: "assets/img/welcome_post.jpg"
})
.then((docRef) => {
console.log("Welcome post created with ID: ", docRef.id);
})
.catch((error) => {
console.error("Error creating post: ", error);
});
// ...
});
As explained in the doc, serverTimestamp returns a sentinel used with set() or update() to include a server-generated timestamp in the written data.
The term sentinel means that the exact value is calculated on the back-end, i.e. on the Firestore platform when the document is written to Firestore. This is why you cannot use this value with e.g. -Math.abs().
The advantage of using serverTimestamp instead of a timestamp value generated on the client (e.g. Date.now()) is that the value is independent from the settings and time zones of the users computers. The server time will always be taken into account.
In conclusion, you should keep the timestamp value the way you define it, remove the order field and, when querying, use .orderBy("created", "desc") as explained in Dharmaraj's answer.
If you add an UNIX timestamp (or serverTimestamp) in your document you should be able to sort them in descending order.
db.collection("posts")
.orderBy("created", "desc")
.limit(10)
.get()
This query should fetch 10 latest documents i.e. sorts documents by the value of created field in descending order and limits to first 10 results.
While adding the document, you can add timestamp this way:
const timestamp = Date.now()
docRef.add({
created: timestamp,
...otherFields
})
You can use serverTimestamp itself as it has several benefits over Date.now() as explained by @Renaud. When you fetch the document then that created field will be an object as follows:
{
created: {
seconds: 1627370100,
nanoseconds: 0
}
}
You can then use toDate method to convert that to a Javascript Date.
const {created} = snapshot.val()
console.log(created.toDate()) // JS Date object
console.log(Date.parse(created.toDate())) // Timestamp in milliseconds
Off-topic but you should return promises in a cloud function so add a return keyword:
return docRef.add({}).then(() => {
^^^^^^
console.log("Doc added")
return
}).catch((e) => {
console.log(e)
return null
})