Add timestamp insteard auto-geenrated key in firebase document - javascript

I want to be able to query the latest document from the firebase, and I fount that I have to refer to the timestemp.
However in my database I do have auto-generated id's
I did came across this question How to retrieve the last document in a firebase collection. I would also like to get the document fields value and discovered that you can have time stem instead of the keys.
I adding and updating the data to firebase like that:
firebase.firestore().collection(collectionName).add({
data: data,
updated: getDate()
});
firebase.firestore().collection(collectionName).doc().update({
data: data,
updated: getDate()
});
So I wonder how would you achieve using the date as a keys

If you need to a specific string to be the ID of the document, then you can't use add(), and also can't use doc() with no parameters. You will need to build the string yourself, and pass it to doc().
Personally, I don't recommend this. I suggest accepting the random ID, and instead use a server timestamp as a field in the document. You can use that to sort the results of a query, and limit the result set to 1 in order to get the newest document.

Related

How to increment a map value in a Firestore array

I have a firestore firebase database , in which I have a collection users
there is an array in the collection and in the array there is a map
in map there is a field qty.. I want to increment that qty value..
using increment doesnt help as the qty is inside a array index
db.collection("users").doc(checkId).update({
myCart: firebase.firestore.FieldValue.arrayUnion({
qty: firebase.firestore.FieldValue.increment(1),
}),
this is the error Output =>
Uncaught (in promise) FirebaseError: Function FieldValue.arrayUnion() called with invalid data. FieldValue.increment() can only be used with update() and set()
My answer below won't work, given that the qty is in an array. The only way to update an item in an array is to read the entire document, update the item in the array, and then write the entire array with the updated item back to the document.
An alternative would be to use a map instead of an array, and then update the qty using the approach outlined in my (old, and non-working) answer below 👇
You need to specify the full path to the field you're trying to update. So I think in your case, that'll be:
db.collection("users").doc(checkId).update({
"myCart.0.qty": firebase.firestore.FieldValue.increment(1)
}),
The field you want to update is embedded in an array. In this case, you can't use FieldValue.increment(), since it's not possible to call out an array element as a named field value.
What you'll have to do instead is read the entire document, modify the field in memory to contain what you want, and update the field back into the document. Also consider using a transaction for this if you need to update to be atomic.
(If the field wasn't part of an array, you could use FieldValue.increment().)
As of today (29-04-2020)... this is tested by me.
Suppose my data structure is like this:
collection: Users
Any document: say jdfhjksdhfw
It has a map like below
map name: UserPageVisits
map fields: field1,field2,field3 etc
Now we can increment the number field in the map like below:
mapname.field1 etc...
That is use the dot operator to access the fields inside the map just like you would do to an object of javascript.
JAVA Code (Android), update the field using transactions so they can complete atomically.
transaction.update(<documentreference object>,"UserPageVisits.field1",FieldValue.increment(1));
I have just pushed a version of my app which uses this concept and it's working.
Kudos !!
My Best Regards
Previous answers helped me as well, but dont forget about the "merge" property!!! Otherwise it will overwrite your entire array, losing other fields.
var myIndex = 0;
const userRef = db.collection('users').doc(checkId);
return userRef.update({
'myCart.${myIndex}.qty': admin.firestore.FieldValue.increment(1)
}, {
merge: true
});

Firestore data model is inconsistent

I'm trying to save some data in firestore, the data consists of events, each event has a date and each some attendees.
What I'm trying to do now is model it like this events/${eventDate}/${userEmail} and then I would set this with the user's data. However when I try to set this data I get an error saying that the segment number should be even.
When I added another segment in the path (which I didn't want to do):
events/${eventDate}/attendees/${userEmail} I was able to set the data but I wasn't able to retrieve it (trying to retrieve all attendees of a given event date.
// insertion - this worked after some tweaking
this.db.collection('pickups').doc(pickupDate).set({ [email]: userData})
// deletion (this doesn't work - expects even number of segments)
this.db.collection('pickups').doc(`${pickupDate}/${email}`).delete()
// retrieval (works)
this.db.collection('pickups').doc(pickupDate).valueChanges()
Current delete:
this.db.collection('pickups').doc(pickupDate).update({
[email]: firestore.FieldValue.delete()
})
What am I missing here? Isn't this supposed to be like regular JSON?
The path you're currently trying events/${eventDate}/${userEmail} is interpreted as a collection (events) then a document (eventDate) then another document (userEmail).
What you actually have is a collection, document within that collection, field within that document.
It looks like you're adding the email correctly (I would remove the brackets around the word email though), but trying to delete incorrectly. You delete fields like this:
var removeCapital = cityRef.update({
capital: firebase.firestore.FieldValue.delete()
});
You can see the documentation here: https://firebase.google.com/docs/firestore/manage-data/delete-data#fields
The delete may look like this:
this.db.collection('pickups').doc(pickupDate).update({
email: firebase.firestore.FieldValue.delete()
})
It sounds like what you're trying to do is delete a field out of a document. However, this code you have:
this.db.collection('pickups').doc(`${pickupDate}/${email}`).delete()
is trying to build a reference to a collection, then delete it. It's not correct to use collection() and doc() to reference fields in a document. They are just used to build references to documents and collections.
If you want to delete a field in a document, first build a reference to the document that contains the field:
const ref = this.db.collection('pickups').doc(pickupDate)
Then update the document to indicate that you want the field removed:
ref.update({ [email]: firebase.firestore.FieldValue.delete() }}
The way you reference delete() out of FieldValue is going to change based on how you have the SDK imported into your code.
See the documentation on deleting fields for more information.

Set value of field in Firestore document only if the field hasn't already been set

I have a collection whose documents look something like this:
count: number
first: timestamp
last: timestamp
The first value should (almost) never change after the document's creation.
In a batch write operation, I am trying to update documents in this collection, or create those documents that do not yet exist. Something like
batch.setData([
"count": FieldValue.increment(someInteger),
"first": someTimestamp,
"last": someTimestamp
], forDocument: someDocumentRef, mergeFields: ["count","last"])
My hope was that by excluding first from the mergeFields array, Firestore would set count and last by merging it into an existing document or making a new one, and set first only if it had no previous value (i.e., the document didn't exist before this operation). It is clear to me now that this is not the case, and instead first is completely ignored. Now I'm left wondering what the Firestore team intended for this situation.
I know that I could achieve this with a Transaction, but that doesn't tie in very well with my batch write. Are Transactions my only option, or is there a better way to achieve this?
I have created timestamps and other data in my documents and I handle this using separate create and update functions rather than trying to do it all at once.
The initial creation function includes the created date etc and then subsequent updates use the non-destructive update, so just omit any fields in the update payload you do not want to overwrite.
eg. to create:
batch.set(docRef, {created: someTimestamp, lastUpdate: someTimestamp})
then to update:
batch.update(docRef, {lastUpdate: someTimestamp, someOtherField: someData})
This will not overwrite the creationDate field or any other fields, but will create the someOtherField if it does not exist.
If you have a need to do a "only update existing fields" update after the document is created for the first time then currently you have to read the document first to find out if the fields exist and then create an update payload which will patch the only the desired fields. This can be done in a transaction or you can write this logic yourself, depending on your needs.

Append to an arary field in Firestore

I'm using Firebase and Vuejs to create an database element, which has object array inside.
That's how the field looks, and I want to add tasks through the form into the 'moreTasks' as an array.
I tried using this, but it just creates new entity in the database.
db.collection('Tasks').add({
tasker: this.tasker.taskerName
})
I also tried checking API but I couldnt understand the refs, because I was using different methods to achieve that goal.
creatTask() {
db.collection('Tasks').add({
task_id: this.task_id,
name: this.name,
What would be correct way to approach this problem?
You can append an item to an array using FieldValue.arrayUnion() as described in the documentation. For example:
// Atomically add a new region to the "regions" array field.
washingtonRef.update({
regions: firebase.firestore.FieldValue.arrayUnion("greater_virginia")
});
The accepted answer used to be correct but is now wrong. Now there is an atomic append operation using the arrayUnion method:
https://firebase.google.com/docs/firestore/manage-data/add-data#update_elements_in_an_array
This is true as long as you are using firestore and not real time db (which I assume is the case from the tags)

Meteor: retrieve value from document in collection

I have a Collection named "balance". I want to get the value of one document in the collection. In order to get only the latest element in the collection I use this query:
db.balance.find().sort({date: -1}).limit(1);
There's a column called 'value' and I want to get that.
db.balance.find().sort({date: -1}).limit(1).value; however does not show the data I want. It shows nothing:
What's wrong with it?
find returns a cursor. You'll need to convert it to an array in order to actually extract the value. Try this:
db.balance.find().sort({date: -1}).limit(1).toArray()[0].value;
This is, of course, much easier inside of meteor (either in code or via meteor shell) because you can do:
Balance.findOne({}, {sort: {date: -1}}).value;

Categories

Resources