Firestore: Updating field in an object removes previous field - firebase

I am using Flutter cloud firestore. Here is how my database looks like.
I want to add more fields (like "2222") in a_numbers object. I use updateData()like this,
DocumentReference ref = Firestore.instance.document("products/-LMhR5cAyW4T0sa03UtU");
ref.updateData({"a_numbers": {"2222" : false}});
The above snippet basically deletes the previous value (1111) and then updates the database with 2222 field.
Any solution?

To update 'a_numbers' with Pair without removing the previous values, you should assign the reference path (example: 'a_number.2222') to K and assign value to V. I edited your code. please review it for more information.
DocumentReference ref = Firestore.instance.document("products/-LMhR5cAyW4T0sa03UtU");
ref.updateData({'a_numbers.2222': value});

This is the expected behavior, in your Flutter application, you need to store a_numbers in a Map and add any new (key,value) pairs using myMap.addAll({key:value}), then you can use ref.updateData(myMap)

Related

editing document and field in firebase

im working on firebase and im trying to update the document name and its field name together like shown in the image. i want them to be updated together.
i used this code
EditCourse(String cName, String newName) async {
var collection = FirebaseFirestore.instance.collection("Courses")
..where("Course name", isEqualTo: cName);
collection.doc(cName).update({'Course name': newName});
}
Answer:
As of Now Firebase not allows to update documents ids)
Suggestion:
You should use relational ids or random ids
(relational ids means suppose you have seller favorite collection you can give documents ids to movie/food ids)
There is no way to update the document ID of an existing document. If changing course names is a use-case you need to support, consider using Firestore's built-in ID generation when adding your documents (so add documents using the add() method).
If you stick to your current model, you'll have to:
Read the existing document.
Write the date under the new ID.
Delete the original document.
Given the type of operation, you'll probably want to use a transaction for that.

Deleting data that all users use but only for one user in Cloud Firestore

I am trying to structure my data such that when someone adds a new product to the database, all users receive the new product in their list and therefore the new product appears on their screen.
But if a user decides to delete that product, they can delete it but only for themselves. Is there a Cloud Firestore sorting/ordering/filtering that I should be using to accomplish this?
I thought I could use something like the following:
final theProduct = Provider.of<Products>(context);
products = await firestore.collection('products').getDocuments()
for (product in products.documents) {
await firestore.collection('products').add({
'nameOfProduct': theProduct.nameOfProduct
});
}
But I get a document property error.
Maybe I need to go in one more collection and then try something? But I also need to be able to retrieve the data back using the userID of the signed in user..
Any hints/helpful links would be greatly appreciated.
So I think what I want to do is iterate through all documents within a collection and then document().collection('').add() something to each of their collection. Hopefully that sheds some more light on my problem.
Thanks to those who commented. I found a way to implement this was to use the unique value that each product contains and add it to a list on a per user basis in Firestore. Then fetch that list from Firestore and filter out the corresponding products. No deleting necessary.
Question : a user decides to delete that product, they can delete it but only for themselves
Answer: U can create list in user profile section where u can have all the product document ids & u can use that document id to fetch particular product details & when user click on delete button u can remove that particular document id from there collection
Im not sure what r u doing with sample code over there.
If u want to add data to database then use :
await Firestore().collection('Products').add({
'nameOfProduct': theProduct.nameOfProduct,
});
this will generate document random id for your product.
To get data from particular id use :
DocumentSnapshot documentSnapshot = await Firestore().collection('Products').document('document').get();
then u can use that document snapshot to get data for particular key e.g.
documentSnapshot.data['Product Name']

Would executing the below given code will delete all the previous data?

What if some data is already there inside the users collection ?
Would doing this 👇🏻 will delete all the previous data ?
var messageRef = db.collection('users').doc(userID)
.collection('private_user_data').doc(userID);
I want to add new data inside users collection and inside that a doc with 4 fields and one more collection inside that and inside that a doc with four more fields.
The code in your question doesn't read from or write to the database in any way. It merely sets up a reference to a document in the database.
There are few ways to implement this, depending on your exact use-case:
To merge data with an existing document, use the update method.
If the document may or may not exist, you can tell Firestore to merge the new values with the existing data when you call the set method.
If you want to set some fields only if the document doesn't exist yet, and leave them unmodified if the document already exists, you will need to use a transaction. In that case you may also want to make sure your security rules reject modifications to those initial fields.
With your code you don't make any operation on your db.
If you would know use .set(someData) your document would be created with given data if there is no document with given id or the document would be overwritten with the given data if there is a document with the given id.
Please check this post from the Firebase docs for more information.
EDIT
To create a document you have to do something like this:
var messageRef = db.collection('users').doc(userID)
.collection('private_user_data').doc(userID);
messageRef.set({
field1: input1,
field2: input2,
field3: input3,
field4: input4
})
Be aware that messageRef.set() will return a promise. So you have to deal with it. And here I would recommend you one of the tutorials from the Firebase team or one of many from the Internet.

Firebase Firestore Documents changes history (like Activity log/ History for changes in each Doc)

I'm trying to make an Activity log system or history for my docs, so every time a field is modified in a document i want to record or save that so i can see after changes history made on each document.
how i can achieve that ? i don't want to save the full doc on each change and then have tons of duplicated docs, if possible i just want to get the changed field (ex. name: 'john' -> name: 'jack').
i don't want to save the full doc on each change and then have tons of duplicated docs
Once a document has changed it becomes a new document. So you won't have duplicate documents unless you make changes that were previously made. Please also note that in Cloud Firestore there are no field-level permissions or access to a document. It's the entire document, or nothing. So if you want to change a field within a document for example from:
userName = "John"
into
userName = "Jack"
You'll will get the entire document and not only the userName property that has been changed.
Cloud Firestore listeners fire on the document level. There is no way to get triggered with just particular fields in a document.
If you want to get notified only of specific fields, consider adding an extra collection with documents that only contain those fields. This sort of data duplication is quite common in NoSQL solutions such as Firestore and for that, I recommend you see this video, Denormalization is normal with the Firebase Database for a better understanding. It is for Firebase real-time database but same principles apply to Cloud Firestore.
For a database schema you can also take a look at my answer from this post.
The best way to achieve something like this is to store the before and after changes happening to the doc, in a new document, which you can add in a subcollection. The changes are available with cloud functions onUpdate trigger. I have written in depth about this topic on my blog, have a look.
https://blog.emad.in/audit-logs-for-firestore-documents/
You can obtain this by creating a cloud function that triggers on all document updates in all collections:
--trigger-resource=projects/$PROJECT_ID/databases/(default)/documents/{collection_id}/{document_id}
In the cloud function you can obtain all the updated fields and their values through the data object.
Python example:
def main(data, context):
# Extract resource
resource = context.resource
resource_split = resource.split('/')
collection_name = resource_split[-2]
document_id = resource_split[-1]
# Get old fields
data_old_values = data['oldValue']
data_old_values_fields = data_old_values['fields']
# Get updated fields
data_updated_mask = data['updateMask']
data_updated_fields = data_updated_mask['fieldPaths']
# Get new field values
data_new_values = data['value']
data_new_values_fields = data_new_values['fields']
# `data_updated_fields` is a list of the fields that has been changed
# `data_old_values_fields` is a dictionary with the old values of the document
# `data_new_values_fields` is a dictionary with the new values of the document

Find object in Firebase by one value

I have next database list (usernames + user id).
How can i find object by user id and change his key (username)?
I'm using AngularFire2 with Angular 5.
You can find a child node by its value with a query like this:
var users = firebase.database().reference("usernames");
var query = users.orderByValue().equalTo("Sk6I..."ltA2");
By attaching a listener to this query you'll be able to find the reference and the key of the user (or "any users", since technically there may be more keys with the same value) matching the UID.
But you can't rename a node. You'll have to remove the existing node, and create a new one. For more on this see:
Firebase: Update key?
Firebase API for moving a tree branch from a collection to another one
Is it possible to rename a key in the Firebase Realtime Database?
Solution for my case:
this.db.list('usernames', ref => ref.equalTo(uid)).remove() // Remove old value
this.db.list('usernames', ref => ref.equalTo(uid)).set(
username, uid
) // Create new value

Resources