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.
Related
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.
So this is possible:
const docSnapshot = await firebase.firestore().collection("SOME_COL").doc("SOME_DOC").get();
console.log(docSnapshot.exists);
But it "downloads" the whole document just to check if it exists. And I'm currently working with some havier documents and I have a script where I just need to know if they exist, but I don't need to download them at that time.
Is there a way to check if a document exist without .get() and avoid downloading the document data?
It seems you are using the JavaScript SDK. With this SDK there isn't any way to only get a subset of the fields of a document.
One of the possible solutions is to maintain another collection with documents that have the same IDs than the main collection documents but which only hold a very small dummy field. You could use a set of Cloud Functions to synchronise the two collections (Documents creation/deletion).
On the other hand, with the Firestore REST API, it is possible, with the get method, to define a DocumentMask which defines a "set of field paths on a document" and is "used to restrict a get operation on a document to a subset of its fields". Depending on your exact use case, this can be an interesting and easier solution.
I have two collection in firebase, say A and B. When I add an item to one of the collections, say A, it automatically adds to another collection B. But when I delete an item from collection A, it remains in the other collection B.
Shot from firebase console
When I delete an item from collection A, it remains in the other collection B.
I am unable to figure out how to make the items deleted in both collections?
Please help.
This is no relational DB. Cascadate updates/deletes are possible in relational DBs like Sql, Postgresql, Firebird... In No-SQL You do not have any relations one document to another. What' more it is desirable to have some data cloned in two or more documents rather than creating a separate doc for it.
But maybe You can achieve what You want by using reference type? I sow it once or twice, it might be a good idea to check it out. But be the description it is only a field with path/reference, no magic here.
By the official doc:
If you want to delete documents in subcollections when deleting a parent document, you must do so manually, as shown in Delete Collections.
So You either want to rethink The DB model or have to manualy track each wlement You want to delete.
You have two ways to do that:
From client side use batch write (more here)
DocumentReference doc_1_reference = firestore.collection("messages").document(doc_1_uid);
DocumentReference doc_2_reference = firestore.collection("messages").document(doc_2_uid);
final batchWrite = firestore.batch();
batchWrite.delete(doc_1_reference);
batchWrite.delete(doc_2_reference);
await batchWrite.commit();
Using Cloud functions by adding a delete trigger to the documents, and perform the deletion of the other document when triggered. Given you have away to know which document you're supposed to delete which is not difficult to do (read about it here)
I am trying to achieve a scenario where firebase triggers only once when a collection is created and not every time that a document is added to the collection. Let's say I want it to trigger only for the first document added to the collection and not for every other document added to the same collection. How can that be done? Please help !!!
There is no such trigger for Cloud Functions. Your trigger path must specify exactly one document, or use wildcards to specify a path that could possibly match many documents.
If you want to know what a collection contains its first document, you will have to either:
Maintain a count of documents in that collection (perhaps in yet another document in another collection), and trigger of the change of that value when it goes from 0 to 1.
Query all of the documents in the collection where a document was just created in order to figure out if it was the first one.
Both of these requires a fair amount of extra code - very much not trivial to implement correctly for arbitrary collections. They could also run into problems under heavy load. If these options won't work for you, I suggest figuring out another way to get you function to trigger at the right time.
While It's not possible to do directly. You can check if collection contains any elements, and if it does it means that it exists.
const result =await firestore.collection("collection").limit(1).get()
if(result.size){
// Collection exists
}
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