I'm trying to get a collection in Firebase and turn it into a List of Strings and make some conditions with it. I'm creating an app for a store and my intention is applying a way to create a list of favorites, for each user, when I press a button in a product. To add a favorite product in firebase, i'm using this, and it's working:
_saveFavorite(Product product) async {
await _loadCurrentUser(); //So I get the user ID
Firestore db = Firestore.instance;
db.collection("my_favorites")
.document(_userID)
.collection("products")
.document(product.id)
.setData(product.toMap());
}
To remove the favorite product, I'm using this:
_removeFavorite(String productID) async {
await _loadCurrentUser();
Firestore db = Firestore.instance;
db.collection("my_favorites")
.document(_userID)
.collection("products")
.document(product.id)
.delete();
}
So, this is the way: Collection("my_favorites") > Document (userID) > Collection ("products") > Document (productID) > products save as favorites.
I'm trying to get all the productsID saved in Collection("products") to make a condition for a raised button, but I don't know how to do it. I want to press this button and make a condition like: ListOfIDProducts.contains(product.id) ? _removeFavorite : _saveFavorite;
Thanks for your attention and if you could help me, I appreciate it very much!
You could store such a list inside of the /my_favorites/USER_ID
document as an array of currently favorited product IDs. You could maintain this list using a Cloud Function as each product is added and removed from the /my_favorites/USER_ID/products
collection, but it's arguably simpler to just make use of a batched write along with the array field transforms, arrayUnion()
and arrayRemove()
.
_saveFavorite(Product product) async {
await _loadCurrentUser();
Firestore db = Firestore.instance;
WriteBatch batch = db.batch();
// queue adding the product's ID to the products array
batch.update(
db.collection("my_favorites")
.document(_userID),
{
products: FieldValue.arrayUnion([product.id])
}
);
// queue uploading a copy of the product's data to this user's favorites
batch.set(
db.collection("my_favorites")
.document(_userID)
.collection("products")
.document(product.id),
product.toMap()
);
return batch.commit();
}
_removeFavorite(String productID) async {
await _loadCurrentUser();
Firestore db = Firestore.instance;
WriteBatch batch = db.batch();
// queue removing product.id from the products array
batch.update(
db.collection("my_favorites")
.document(_userID),
{
products: FieldValue.arrayRemove([product.id])
}
);
// queue deleting the copy of /products/PRODUCT_ID in this user's favorites
batch.delete(
db.collection("my_favorites")
.document(_userID),
.collection("products")
.document(product.id)
);
return batch.commit();
}
To get the list of product IDs, you would use something similar to:
_getFavoriteProductIDs() async {
await _loadCurrentUser();
Firestore db = Firestore.instance;
return db.collection("my_favorites")
.document(_userID)
.get()
.then((querySnapshot) {
return querySnapshot.exists ? querySnapshot.get("products") : []
});
}
You could even convert it to work with lists instead:
_saveFavorite(List<Product> products) async {
if (products.length == 0) {
return; // no action needed
}
await _loadCurrentUser();
Firestore db = Firestore.instance;
WriteBatch batch = db.batch();
// queue adding each product's ID to the products array
batch.update(
db.collection("my_favorites")
.document(_userID),
{
products: FieldValue.arrayUnion(
products.map((product) => product.id).toList()
)
}
);
// queue uploading a copy of each product to this user's favorites
for (var product in products) {
batch.set(
db.collection("my_favorites")
.document(_userID)
.collection("products")
.document(product.id),
product.toMap()
);
}
return batch.commit();
}
_removeFavorite(List<String> productIDs) async {
if (productIDs.length == 0) {
return; // no action needed
}
await _loadCurrentUser();
Firestore db = Firestore.instance;
WriteBatch batch = db.batch();
// queue removing each product ID from the products array
batch.update(
db.collection("my_favorites")
.document(_userID),
{
products: FieldValue.arrayRemove(productIDs)
}
);
// queue deleting the copy of each product in this user's favorites
for (var product in products) {
batch.delete(
db.collection("my_favorites")
.document(_userID)
.collection("products")
.document(product.id)
);
}
return batch.commit();
}
Additional note: With your current implementation, a favourited product is copied from /products/PRODUCT_ID
to /my_favorites/USER_ID/products/PRODUCT_ID
. Remember that with this structure, if /products/PRODUCT_ID
is ever updated, you will have to update every copy of that product. I suggest renaming products
to favorited-products
so that you can achieve this using a Cloud Function and a Collection Group Query (see this answer for more info).