I have a collection named "departments" with a subcollection inside named "users". I want to delete all the documents in "departments" without documents in the users sub-collection or without the sub-collection users.
Any ideas of how to find the documents to delete?
Thanks!
Assuming you have a structure that looks like this:
Firestore-root
|
--- departments (collection)
|
--- $departmentId (document)
|
--- users (collection)
|
--- $uid (document)
|
--- //user data
To be able to achieve this:
I want to delete all the documents in "departments" without documents in the users sub-collection.
You have to get all documents in the users sub-collection and delete them. But remember, such an operation is not really recommended by the Firebase team to be done on the client, if you have a large number of documents inside your collection. However, for a small number of documents, it will work.
The most important thing in this operation is that if you delete those documents, the sub-collections will continue to exist, and deleted documents will be displayed in italic.
Only in the Realtime Database, if you delete a node, you delete it with all the data that exists beneath it. But here is not the case, so no worries.
To be able to delete documents that don't have subcollection, you must query the departments collection and iterate the documents to check whether they have the subcollection users on it. See sample code below:
const db = getFirestore();
// `departments` reference.
const departmentsRef = query(collection(db, "departments"));
// Gets all documents from the department's reference.
const querySnapshot = await getDocs(departmentsRef);
// Iterate the documents.
querySnapshot.forEach(async (doc) => {
// `users` reference.
const usersRef = query(collection(db, "departments", doc.id, "users"));
// Check if the document has the `users` collection
const querySnapshot = await getDocs(usersRef)
.then((usersDoc) => {
// Check if the `users` subcollection exists
// Also counts the documents of the subcollection.
if (!usersDoc.size) {
// Deletes the document from the document reference.
deleteDoc(doc.ref);
}
});
});
Related
In the 1st screen shot there are many documents in collection users. Each documents contains further collection jobPost and that collection contains further documents and its meta data.
What I want here is go to the every document of collection users and further subcollection jobPost and fetch all the documents.
Suppose first it should go to document 1 in collection users, in the document 1 it should fetch all the documnets in subcollection jobPost then it should go to the 2nd document of collection users and then get all the documents in the subcollection jobPost and so on. what will be the query or implementation to this technique
What you're describing is known as a collection group query, which allows you to query all collections with a specific name. Unlike what the name suggests, you can actually read all documents from all subcollections named jobPost that way with:
FirebaseFirestore.instance.collectionGroup('jobPost').get()...
When performing a query, Firestore returns either a QuerySnapshot or a DocumentSnapshot.
A QuerySnapshot is returned from a collection query and allows you to inspect the collection.
To access the documents within a QuerySnapshot, call the docs property, which returns a List containing DocumentSnapshot classes.
But subcollection data are not included in document snapshots because Firestore queries are shallow. You have to make a new query using the subcollection name to get subcollection data.
FirebaseFirestore.instance
.collection('users')
.get()
.then((QuerySnapshot querySnapshot) {
querySnapshot.docs.forEach((doc) {
FirebaseFirestore.instance
.document(doc.id)
.collection("jobPost")
.get()
.then(...);
});
});
**
if you not have field in first collection document then its shows italic thats means its delte by default otherwise if you have field in first collection document then you can access it easily so this is the best way that i share
**
static Future<List<PostSrc>> getAllFeedPosts()async
{
List<PostSrc> allPosts = [];
var query= await FirebaseFirestore.instance.collection("posts").get();
for(var userdoc in query.docs)
{
QuerySnapshot feed = await FirebaseFirestore.instance.collection("posts")
.doc(userdoc.id).collection("userPosts").get();
for (var postDoc in feed.docs ) {
PostSrc post = PostSrc.fromDoc(postDoc);
allPosts.add(post);
}
}
return allPosts;
}
this is my function for deleting a document in my "files" collection
Future<void> deleteProgram(String id, String program) async {
try {
print(id + "----" + program);
await firestoreInstance.collection("files").doc(program).delete();
// await firestoreInstance.collection("programs").doc(id).delete();
print("done");
} catch (e) {
print(e);
}
}
program is the id of the document, when i use this nothing gets deleted, even if i hardcode the ID.
this is what my collection looks like:
as you can see, each document in the files collection also has a subcollection called files
what am i doing wrong here?
The only way to delete a collection is to delete each individual document from it. There is no atomic operation to delete a collection.
In your screenshot the opleiding4 is shown in italic, meaning that this document doesn't really exist, and the Firebase console merely shows that name to be able to show its files subcollection.
Once you delete all files from the /files/opeleiding4/files subcollection both that collection and its parent document will disappear from the Firebase console too.
Also see:
Firestore DB - documents shown in italics
How to recursively delete collection in firestore?
How to Delete all documents in collection in Firestore with Flutter
I am using Cloud Firestore as my database and I have collections of users where are stored basic information about user such as id, name, last name, email, company id.
Also I have collection of companies and in each company I have collection of tasks.
In each task I have one user assigned from collections of users (user data is replicated, so I have same data for that user as in collection users)
The problem is when I update user (change name or email...) from collection users because data is replicated that data is not changed in collection of tasks for that specific user.
Is there any way that using firestore when user from collection users is updated to automatically update it in collection of tasks?
This is quite a standard case in NoSQL databases, where we often denormalize data and need to keep these data in sync.
Basically you have two possible main approaches:
#1 Update from the client
When you update the "user" document, update at the same time the other documents (i.e. "tasks") which contain the user's details. You should use a batched write to do so: A batch of writes completes atomically and can write to multiple documents.
Something along the following lines:
// Get a new write batch
var batch = db.batch();
var userRef = db.collection('users').doc('...');
batch.update(userRef, {name: '....', foo: '....'});
let userTaskRef = db.collection('companies').doc('...').collection('tasks').doc('taskId1');
batch.update(userTaskRef, {name: '....'});
userTaskRef = db.collection('companies').doc('...').collection('tasks').doc('taskId2');
batch.update(userTaskRef, {name: '....'});
// ...
// Commit the batch
batch.commit().then(function () {
// ...
});
Note that you need to know which are "the other ("tasks") documents which contain the user's details": you may need to do a query to get these documents (and their DocumentReferences).
#2 Update in the back-end via a Cloud Function
Write and deploy a Cloud Function that is triggered when any "user" document is updated and which takes the value of this "user" document and update the "tasks" documents which contain the user's details.
Like for the first approach, you also need, in this case, to know which are "the other ("tasks") documents which contain the user's details.
Following your comment ("Is there any option to reference to another table or put foreign key?") here is a Cloud Function that will update all the ("tasks") documents that have their DocumentReference contained in a dedicated Array field taskRefs in the "user" doc. The Array members are of data type Reference.
exports.updateUser = functions.firestore
.document('users/{userId}')
.onUpdate((change, context) => {
const newValue = change.after.data();
const name = newValue.name;
const taskRefs = newValue.taskRefs;
const promises = taskRefs.map(ref => { ref.update({ name: name, foo: "bar" }) });
return Promise.all(promises);
});
You would most probably set the value of this taskRefs field in the "user" doc from your frontend. Something along the following lines with the JS SDK:
const db = firebase.firestore();
db.collection('users').doc('...').set({
field1: "foo",
field2: "bar",
taskRefs: [ // < = This is an Array of References
db.collection('tasks').doc('....'),
db.collection('tasks').doc('....')]
});
I need to query fields and get all sub-collections and fields. Is it possible?
Stream<List<ChatFieldModel>> getChatField(String uid) {
var ref = _db.collection('chats')
.where('toUserId', isEqualTo: uid);
//Afterthat need to get sub collection with sub collection list of documents and main collection fields value. is it possible?
return ref.snapshots().map((list) => list.documents
.map((doc) => ChatFieldModel.fromForestore(doc))
.toList());
}
Firestore queries are shallow. They only return documents from the collection that is (or, if you use collection group queries, the collections that are) being queried.
So if you're querying chats, you will only get documents from that collection. To load documents from the messages subcollection you will need to perform an additional query/read operation.
I have field users in document and this field contains two element in array. I have to check specific two values are in this array.
First, I used array-contains method twice for this, but it occurred error.
How can I access index of array field in Cloud Firestore?
Below code is my approach and it is not working:
QuerySnapshot querySnapshot = await sl.get<FirebaseAPI>().getFirestore()
.collection('messages')
.where('users'[0],isEqualTo: 'user1ID')
.where('users'[1],isEqualTo: 'user2ID')
.getDocuments();
simple firestore structure
There is no way Firestore in which you can query the database based on an index of an element that exist within an array. It's true that you cannot chain more than one array-contains calls in a query but there is another workaround that can help you achieve the same thing. So a change is needed in your database structure. So instead of using an array you can use a map and your schema should look similar to this:
Firestore-root
|
--- messages (collection)
|
--- users (map)
|
--- user1ID: true
|
--- user2ID: true
Now a query like this will work perfectly fine:
QuerySnapshot querySnapshot = await sl.get<FirebaseAPI>().getFirestore()
.collection('messages')
.where('users.user1ID',isEqualTo: true)
.where('users.user2ID',isEqualTo: true)
.getDocuments();