firebasefirebase-realtime-databasegoogle-cloud-firestorefavorites

How to turn a collection in Firebase into a List of Strings and make some conditions with it


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!


Solution

  • 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).