Remove referenced document from array Field list type in a document - flutter

I have a collection in firebase called "community" and "users". All user records have a field "joinedCommunity" (a list of all joined communities).
I'm trying to figure a code that when a community is deleted, all user records are updated to only remove the community reference from "joinedCommunity" field list.
building this in flutterflow using custom action
onTap on a button in UI, the code is included as one of the actions before community document is deleted.
Future userRecordUpdate(DocumentReference community) async {
final instance = FirebaseFirestore.instance;
final batch = instance.batch();
var collection = instance.collection('users');
batch.update(collection, {
"joinedCommunity": FieldValue.arrayRemove([community])
});
await batch.commit();
}

You're using a CollectionReference, when what you want is a DocumentReference. As per the documentation, WriteBatch.update only works on a DocumentReference.
I have a few suggestions:
Try updating the field without using a WriteBatch. Use a for loop and a regular DocumentReference.update() call.
Then, update your code to use a WriteBatch to update the field. Also, keep in mind a batch is limited to 500 operations.
Finally, consider the security implications of allowing a client to be able to update any User document. You should probably update your security rules so that a user document can only be modified by that user. This code is probably something that should run in a Firebase Cloud Function that gets triggered whenever a community document is deleted.

the following code worked -
Future userRecordUpdate(DocumentReference community) async {
final instance = FirebaseFirestore.instance;
final batch = instance.batch();
var collection = instance.collection('users');
var snapshots =
await collection.where("joinedCommunity", arrayContains:
community).get();
for (var doc in snapshots.docs) {
batch.update(doc.reference, {
"joinedCommunity": FieldValue.arrayRemove([community])
});
}
await batch.commit();
}

Related

How can I get the document from Firebase Firestore with particular value in field?

I'm creating todo list in which I'll have two lists one for incomplete tasks and another for completed tasks...I'm able to retrieve the data from Firestore by pulling the whole data without any condition, but for the uncompleted list, I want to retrieve the document only with particular field values. For example, each document contains the following fields as shown in the picture:
Here is the code which I've used to get the data from firebase firestore:
static List<Task> getTasks() {
//convert firebase collection to list
List<Task> tasks = [];
FirebaseFirestore.instance.collection('Todos').snapshots().listen((data) {
data.docs.forEach((doc) {
tasks.add(Task.fromMap(doc.data()));
});
});
return tasks;
}
I want similar function like this to retrieve only documents with taskStatus == true. So, I can store all those tasks which have taskStatus of true on separate list and display them accordingly.
You can use the where function. It works like below.
For more: Cloud FireStore Filtering
FirebaseFirestore.instance
.collection('Todos')
.where('taskStatus', isEqualTo: true)
.snapshots().listen((data) {
data.docs.forEach((doc) {
other_tasks.add(Task.fromMap(doc.data()));
});
});

How do I only return my primary keys from a Firebase RTDB and not the rest of the data stored when using a get() in Flutter?

My menu item tree looks is shown below:
menuItem
J1
-description:"Tasty milk shake!"
-img:"assets/images/milkshake.JPG"
-itemName:"Milk Shake"
-price:20
-varieties
-var1:"Chocolate"
-var2:"Vanilla"
-var3:"Strawberry"
I want to get just the item IDs (J1, J2, J3 ect.) but not all the information such as 'itemName'
final DatabaseReference _dbRef = FirebaseDatabase.instance.ref();
final items = await _dbRef.child('menuItem').get();
if (items.exists) {
String? itemID = items.value.toString();
}
items.values returns all the information for an item and items.key returns only 'menuItem'.
How can I just get the IDs only?
With the Realtime Database queries done via the Client SDKs are deep: They always return the entire subtree.
This is a key difference with Firestore for which queries are shallow: They only return documents in a particular collection or collection group and do not return subcollection data.
However, with the Realtime Database REST API you can use a query parameter named shallow, which "limits the depth of the data returned at a location". I've never used it but it seems that it will fulfill your requirement.
Another solution would to denormalise your data and maintain, in parallel to the menu items, a list of menu IDs in a specific DB node.
As Renaud explained in his answer, all read operations in the Firebase Realtime Database SDKs return complete branches of the tree, and can't be used to just read the keys.
That said, you can use just the keys from the data you read with:
final DatabaseReference _dbRef = FirebaseDatabase.instance.ref();
final items = await _dbRef.child('menuItem').get();
items.forEach((child) => {
console.log(child.key);
})
The above will still retrieve the entire menuItem branch of your database, but only show the keys under that node (so J1 from the sample you shared).

How can I get a collection inside a QuerySnapshot

On the explore page, I get() the entire users collection to create a user list and search results. Inside each of those user documents is a collection posts that I also need to get to create a GridView of each post. I want to reuse that users collection QuerySnapshot instead of fetching each posts collection again to save money. Is this possible?
Here is my current function:
void fetchUsers() async {
final userRef = FirebaseFirestore.instance.collection('users');
final QuerySnapshot result = await userRef.get();
final docs = result.docs.asMap();
docs.forEach((index, value) {
final profile =
ProfileObject.fromJson(value.data() as Map<String, dynamic>);
usersList.add(UserSearchResult(profile, value.id));
/// Below is the code for getting the posts, not working, need ideas
final QuerySnapshot postsResult = value.get('posts');
final posts = postsResult.docs.asMap();
posts.forEach((index, value) {
final post = Post.fromJson(value.data() as Map<String, dynamic>);
postsList.add(post);
});
});
print(usersList);
print(postsList);
}
Here is the structure of my Firestore:
users
uid (doc)
posts (collection)
info (fields)
uid (doc)
posts (collection)
info (fields)
It is not possible to call a collection to get all sub-collections. You should restructure your database to include sub-collection data in document itself. You can use a map or list for that. But remember, calling everything in one go may end up in slow performance and you might end up losing your customers. So the best way is to include the info in every posts' documents. That way, you won't loss your money and user won't feel lag in performance.
It is not possible. You fetch a document, then fetch the (sub)collection under it.
Subcollection data are not included in the initial document snapshots because Firestore queries are shallow. There shouldn't be any cost savings that you can do there?
See the similar Q&A:
Firestore: Get subcollection of document found with where

How to arrange documents in Firestore using Flutter through custom document IDs?

I want to order the documents in Firestore. The default Firestore documents list consist of alphabetic characters which get created automatically. But I don't want that. I just want to see my newly added document added at the top of my documents list. How do I do that in flutter? It would be very helpful if you provide me with a code for that. The code I use to create a collection is:
Future<void> userSetup() async {
String user = FirebaseAuth.instance.currentUser?.displayName as String;
CollectionReference users = FirebaseFirestore.instance.collection(user);
final hours = time?.hour.toString().padLeft(2, '0');
final minutes = time?.minute.toString().padLeft(2, '0');
users.add({
"customerId": FirebaseAuth.instance.currentUser?.uid.toString(),
"customerName": FirebaseAuth.instance.currentUser?.displayName,
"customerEmail": FirebaseAuth.instance.currentUser?.email,
"selectedTime": '${hours}:${minutes}',
"selectedDate": DateFormat('dd/MM/yyyy').format(date!),
});
return;
}
But I am unable to set my own document id. Please help me with the issue. Thanks in Advance
From the Flutterfire documentation, the set() method is the one you should be using to be able to specify your own document IDs instead of add(). Keep in mind that if the document ID you specify already exists in your database, the whole existing document will be replaced. This is a sample usage as found in the documentation:
CollectionReference users = FirebaseFirestore.instance.collection('users');
Future<void> addUser() {
return users
.doc('ABC123')
.set({
'full_name': "Mary Jane",
'age': 18
})
.then((value) => print("User Added"))
.catchError((error) => print("Failed to add user: $error"));
}
It seems that documents are ordered alphabetically in the Firestore console, so your custom document IDs should follow alphabetical order as you require. Not to be confused with retrieving documents from Firestore in a particular order, which is done with the orderBy() method.

I am trying to use a field from the collection 'profile' say 'username' to filter the records from the main collection 'orders'

Is there a way to achieve this?
i have tried to assign the entry to a local variable but it doesn't work with crudmethods.
getData() async {
String userId = 'userId';
Firestore.instance.collection('user').document(userId).snapshots();
var snapshot;
var userDocument = snapshot.data;
String _myAddress = userDocument["address"];
return Firestore.instance
.collection('letters')
.where("source Box", isEqualTo: _myAddress)
.snapshots();
}
Yes, you should be able to use a document in the query of another document.
For this, you need to create a reference for one collection and use it in another one.
The below code is an example that you can give it a try adapting further for your case, but that I believe should help you.
// Create references to the profile and orders collections
var profilesRef = db.collection("profile");
var ordersRef = db.collection("orders");
// Create a query against the collection.
var query = ordersRef.where("username", "==", ).doc("username").get();
In the documentation Perform simple and compound queries in Cloud Firestore, there is more information and example of queries that should help you.
In addition to that, this below post from the Community can provide you some insights on how to achieve this type of query as well.
How can I get specific document data from firestore querysnapshot?
Let me know if the information helped you!