Firebase + Ionic 3 - Need Advices/Help to retrieve datas

Hi there!

I’d like to have some advices for my Ionic/Firebase application.

I use Ionic 3
I’m connected to Firebase

My firebase datas are organized like this.

I’d like to display green datas and red datas like this.

but I don’t succeed …
Finally, here is my code and the result (with no css)

import { Injectable } from '@angular/core';
import firebase from "firebase";

/*
  Generated class for the MycartProvider provider.

  See https://angular.io/guide/dependency-injection for more info on providers
  and Angular DI.
*/
@Injectable()
export class MycartProvider {
    cart=[];
    firedata2 = firebase.database().ref('/shops/uidAuchan/categoryList');
    firedata3 = firebase.database().ref('/shops/uidAuchan/categoryList/uidCatFruits');

    constructor() {
    console.log('Hello MycartProvider Provider');
    }

    getAllCatList() {
        var promise = new Promise((resolve, reject) => {
            this.firedata2.orderByChild('uid').once('value', (snapshot) => {
                let Catdata = snapshot.val();
                let temparr = [];
                for (var key in Catdata) {
                    temparr.push(Catdata[key]);
                }
                resolve(temparr);
            }).catch((err) => {
                reject(err);
            })
        })
        return promise;
    }
    getAllCatListProducts() {
        var promise = new Promise((resolve, reject) => {
            this.firedata3.orderByChild('uid').once('value', (snapshot) => {
                let Productsdata = snapshot.val();
                let temparr = [];
                for (var keyProd in Productsdata) {
                    temparr.push(Productsdata[keyProd]);
                }
                resolve(temparr);
            }).catch((err) => {
                reject(err);
            })
        })
        return promise;
    }
}

import {Component, NgZone} from '@angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { MycartProvider } from '../../providers/mycart/mycart';
import firebase from "firebase";

/**
 * Generated class for the CartListPage page.
 *
 * See https://ionicframework.com/docs/components/#navigation for more info on
 * Ionic pages and navigation.
 */

@IonicPage()
@Component({
  selector: 'page-cart-list',
  templateUrl: 'cart-list.html',
})
export class CartListPage {

    ListCategory = [];
    ProductCategory = [];

    temparrCat = [];
    temparrProd = [];


    constructor(public navCtrl: NavController, public navParams: NavParams, public cartProvider: MycartProvider,
                public zone: NgZone) {
        this.cartProvider.getAllCatList().then((res: any) => {
            this.ListCategory = res;
            this.temparrCat = res;
            console.log(this.ListCategory[0].uid);
        })

        this.cartProvider.getAllCatListProducts().then((res2: any) => {
            this.ProductCategory = res2;
            this.temparrProd = res2;
            console.log(this.temparrProd);
        })
    }


    shopfail()
    {
        this.navCtrl.setRoot('ShopMapPage');
        this.cartProvider.cart = [];
    }
}

<!--
  Generated template for the CartListPage page.

  See http://ionicframework.com/docs/components/#navigation for more info on
  Ionic pages and navigation.
-->
<ion-header>

  <ion-navbar color="hcolor">
    <ion-title>Ma Liste de Courses</ion-title>
  </ion-navbar>

</ion-header>


<ion-content padding>
  <button ion-button round outline (click)="shopfail()">Je me suis trompé de magasin</button>

  <ion-list no-lines>
    <ion-list>
      <ion-item-sliding *ngFor="let key of ListCategory">
        <ion-item >
          <h2>{{key.nomCat}}</h2>
        </ion-item>
      </ion-item-sliding>
    </ion-list>
  </ion-list>

  <ion-list no-lines>
    <ion-list>
      <ion-item-sliding *ngFor="let keyProd of ProductCategory">
        <ion-item >
          <h2>{{keyProd.nom}}</h2>
        </ion-item>
      </ion-item-sliding>
    </ion-list>
  </ion-list>
  coucou

</ion-content>

As you can see, the path is already put in “firedata3” so i can only access to “Fraises” & “Pommes”

If you could help me it will be a miracle …

Thank you for reading this message.

I strongly suggest you have another look at the firebase documentation for structuring your data.

In there is it specified that you should not nest your data (like having a category list into a shop).

Instead you could structure your data like this:

{
	"shops": {
		"uidAuchan": {
			"nomShop": "Auchan",
			"uid": "uidAuchan"
		},
		"uidCarrefour": {
			"nomShop": "Carrefour",
			"uid": "uidCarrefour"
		}
	},
	"categories": {
		"uidCatFruits": {
			"nomCat": "Fruits",
			"uid": "uidCatFruits"
		},
		"uidCatViandes": {
			"nomCat": "Viandes",
			"uid": "uidCatViandes"
		}
	},
	"products": {
		"uidFraises": {
			"nom": "Fraises",
			"uid": "uidFraises"
		},
		"uidPoulet": {
			"nom": "Poulet",
			"uid": "uidPoulet"
		}
	}
}

That’s the base of the structure. Now we need to have associations between nodes and that really depends on your requirements but I’m going to take a guess and say that a category contains multiple products and a shop contains multiple categories so here the structure with the association (again might be different based on your requirements).

{
	"shops": {
		"uidAuchan": {
			"nomShop": "Auchan",
			"uid": "uidAuchan",
			"categories": {
				"uidCatFruits": true,
				...
			}
		},
		"uidCarrefour": {
			"nomShop": "Carrefour",
			"uid": "uidCarrefour",
			"categories": {
				"uidCatViandes": true,
				...
			}
		}
	},
	"categories": {
		"uidCatFruits": {
			"nomCat": "Fruits",
			"uid": "uidCatFruits",
			"products": {
				"uidFraises": true,
				...
			}
		},
		"uidCatViandes": {
			"nomCat": "Viandes",
			"uid": "uidCatViandes",
			"products": {
				"uidPoulet": true,
				...
			}
		}
	},
	"products": {
		"uidFraises": {
			"nom": "Fraises",
			"uid": "uidFraises",
			"category": "uidCatFruits"
		},
		"uidPoulet": {
			"nom": "Poulet",
			"uid": "uidPoulet",
			"category": "uidCatViandes"
		}
	}
}

I’ve added a two way association just for the example too (product has one category and a category has multiple products).

To select your data then, you can get the shop that you are in ("/shops/uidAuchan") and get all the categories uid inside (categories). After that you can select all the products that have the category selected uid (in your example “uidCatFruits”).

You can have a look at angularfire2 and the docs folder for tutorials. This will help you with dealing with firebase.

Again this structure is me guessing what your requirements are, so it might be totally different for you but the main point is that it’s going to be much easier to deal with a flatten data structure with a greater amount of data.

Let me know if I was not clear enough (I know this structure is a bit confusing). If you have any questions let me know.

PS: If you have any trouble with my English explanation I’m French so you can private message me if you want.

First of all,

Thank you very much for your reply.

I have completely understood what you told me.

Here is my problem with this kind of organisation :

A shop can put “Poulet” in “Viandes” category
Another can put “Poulet” in “Volailles” category

But they both can have “Viandes” and “Volailles” categories

So … how to make the difference between “Poulet” => "Viandes => “Auchan” and “Poulet” => “Volailles” => “Carrefour” ?

Take a shot at switching over to Firestore. Nested collections are just fine in that case.

Something like that?

{
	"shops": {
		"uidAuchan": {
			"nomShop": "Auchan",
			"uid": "uidAuchan",
			"categories": {
				"uidCatFruits": {
					"uidFraises": true
				},
				"uidCatViandes": {
					"uidPoulet": true
				},
				...
			}
		},
		"uidCarrefour": {
			"nomShop": "Carrefour",
			"uid": "uidCarrefour",
			"categories": {
				"uidCatVolailles": {
					"uidPoulet": true
				},
				...
			}
		}
	},
	"categories": {
		"uidCatFruits": {
			"nomCat": "Fruits",
			"uid": "uidCatFruits"
		},
		"uidCatViandes": {
			"nomCat": "Viandes",
			"uid": "uidCatViandes"
		},
		"uidCatVolailles": {
			"nomCat": "Volailles",
			"uid": "Volailles"
		}
	},
	"products": {
		"uidFraises": {
			"nom": "Fraises",
			"uid": "uidFraises"
		},
		"uidPoulet": {
			"nom": "Poulet",
			"uid": "uidPoulet"
		}
	}
}

You might have to experiment a bit with this and I’m sure there are others (and better) ways…

Agreed, but it’s still in beta so some companies might not want to touch it before it is released…

1 Like

Yeah exactly …

But in your exemple,

Which category should I put for Poulet? (You put uidCatFruits :S)

Sorry my bad, I forgot to remove that (I updated the previous post)…

Thank you very much, i’m gonna test with this organisation!

I’ll keep you in touch!

So now I have this organization

{
  "categories" : {
    "uidCatFruits" : {
      "nomCat" : "Fruits",
      "uidCat" : "uidCatFruits"
    },
    "uidCatViandes" : {
      "nomCat" : "Viandes",
      "uidCat" : "uidCatViandes"
    },
    "uidCatVolailles" : {
      "nomCat" : "Volailles",
      "uidCat" : "uidCatVolailles"
    }
  },
  "products" : {
    "uidFraises" : {
      "iconProd" : "PATH_TO_ICON",
      "nomProd" : "Fraises",
      "uidProd" : "uidFraises"
    },
    "uidPoulet" : {
      "iconProd" : "PATH_TO_ICON",
      "nomProd" : "Poulet",
      "uidProd" : "uidPoulet"
    },
    "uidSaucisses" : {
      "iconProd" : "PATH_TO_ICON",
      "nomProd" : "Saucisses",
      "uidProd" : "uidSaucisses"
    }
  },
  "shops" : {
    "uidAuchan" : {
      "categories" : {
        "uidCatFruits" : {
          "uidFraises" : true
        },
        "uidCatViandes" : {
          "uidPoulet" : true,
          "uidSaucisses" : true
        }
      },
      "nomShop" : "Auchan",
      "uidShop" : "uidAuchan"
    },
    "uidCarrefour" : {
      "categories" : {
        "uidCatFruits" : {
          "uidFraises" : true
        },
        "uidCatVolailles" : {
          "uidPoulet" : true
        },
        "uidViandes" : {
          "uidSaucisses" : true
        }
      },
      "nomShop" : "Carrefour",
      "uidShop" : "uidCarrefour"
    }
  }
}

So now … How may I display my datas as i want (my 1st post) ?

I will need my icons and names etc

…I think this whole conversation is the primary motivation for Firestore. Though I believe I gained some good habits when Firebase forced me to think flat.

2 Likes

I would suggest working step by step - without a database - just put the data in a provider. After you get it working the way you want then consider using a database.

1 Like

+1 for this. You can structure as fancy as you want and then flatten with normalizr later on if you need to.

Okay, I’m gonna try this!

Thank you all for your responses!

Should I put this topic closed? I don’t know

I have never closed any of the topics I started and don’t even know how to do it.

1 Like

You can accept one of the reply that “solved” your problem (mark it as the solution). In this case, I’m not really sure if any of the post “solved” your issue (We gave you recommendations). I like the approach of @JAR19 where you try and setup “mock” data before you even think of the database.

I was also going to suggest that he data need to be normalised (i.e numeric id’s) and to avoid (where possible) using text field in the database as this increases the volume of data transmitted.

Hello!

I tried to use Firestore (Just for test) but … my probleme is the same than in Firebase …

Here is my Firestore storage :

Here is my code :


/*Provider*/
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import 'rxjs/add/operator/map';

// We MUST import both the firebase AND firestore modules like so
import * as firebase from 'firebase';
import 'firebase/firestore';

@Injectable()
export class DatabaseProvider {



   /**
    * @name _DB
    * @type {object}
    * @private
    * @description     Defines an object for handling interfacing with the
    Cloud Firestore database service
    */
   private _DB : any;



   constructor(public http: HttpClient)
   {
       // Initialise access to the firestore service
       this._DB = firebase.firestore();
   }

   getDocuments(collectionObj : string) : Promise<any>
   {
       return new Promise((resolve, reject) =>
       {
           this._DB.collection(collectionObj)
               .get()
               .then((querySnapshot) =>
               {

                   // Declare an array which we'll use to store retrieved documents
                   let obj : any = [];


                   // Iterate through each document, retrieve the values for each field
                   // and then assign these to a key in an object that is pushed into the
                   // obj array
                   querySnapshot
                       .forEach((doc : any) =>
                       {
                           obj.push({
                               id             : doc.id,
                               Nom_du_Magasin           : doc.data().Nom_du_Magasin,
                               Uid_du_Magasin     : doc.data().Uid_du_Magasin
                           });
                       });


                   // Resolve the completed array that contains all of the formatted data
                   // from the retrieved documents
                   resolve(obj);
               })
               .catch((error : any) =>
               {
                   reject(error);
               });
       });
   }


   getDocuments2(collectionObj : string) : Promise<any>
   {
       return new Promise((resolve, reject) =>
       {
           this._DB.collection(collectionObj)
               .get()
               .then((querySnapshot) =>
               {

                   // Declare an array which we'll use to store retrieved documents
                   let obj : any = [];


                   // Iterate through each document, retrieve the values for each field
                   // and then assign these to a key in an object that is pushed into the
                   // obj array
                   querySnapshot
                       .forEach((doc : any) =>
                       {
                           obj.push({
                               id            : doc.id,
                               Nom_Categorie           : doc.data().Nom_Categorie
                           });
                       });


                   // Resolve the completed array that contains all of the formatted data
                   // from the retrieved documents
                   resolve(obj);
               })
               .catch((error : any) =>
               {
                   reject(error);
               });
       });
   }


  getDocuments3(collectionObj : string) : Promise<any>
   {
       return new Promise((resolve, reject) =>
       {
           this._DB.collection(collectionObj)
               .get()
               .then((querySnapshot) =>
               {

                   // Declare an array which we'll use to store retrieved documents
                   let obj : any = [];


                   // Iterate through each document, retrieve the values for each field
                   // and then assign these to a key in an object that is pushed into the
                   // obj array
                   querySnapshot
                       .forEach((doc : any) =>
                       {
                           obj.push({
                               id             : doc.id,
                               Nom_Produit           : doc.data().Nom_Produit
                           });
                       });


                   // Resolve the completed array that contains all of the formatted data
                   // from the retrieved documents
                   resolve(obj);
               })
               .catch((error : any) =>
               {
                   reject(error);
               });
       });
   }
}

/*Home.ts*/
import { Component } from '@angular/core';
import { NavController, AlertController } from 'ionic-angular';
import { DatabaseProvider } from '../../providers/database/database';

@Component({
    selector: 'page-home',
    templateUrl: 'home.html'
})
export class HomePage {
    /**
     * @name locations
     * @type {any}
     * @public
     * @description      Property to store the returned documents from the database collection
     */
    public locations     : any;
    public locations2     : any;
    public locations3     : any;


    /**
     * @name _COLL
     * @type {string}
     * @private
     * @description      Defines the name of the database collection
     */
    private _COLL 		: string 			= "Shops";
   private _COLL2 		: string 			= "Shops/Ze1F64qzERe54/Categories";
    private _COLL3 		: string 			= "Shops/Ze1F64qzERe54/Categories/D2Y4yTUXXdTLqVj3IL41/Produits";

constructor(public navCtrl  : NavController,
                private _DB     : DatabaseProvider,
                private _ALERT  : AlertController)
    {
    }

    ionViewDidEnter()
    {
        this.retrieveCollection();
       this.retrieveCollectionCat();
        this.retrieveCollectionProd();
    }
    /**
     * Retrieve all documents from the specified collection using the
     * getDocuments method of the DatabaseProvider service
     *
     * @public
     * @method retrieveCollection
     * @return {none}
     */
    retrieveCollection() : void
    {
        this._DB.getDocuments(this._COLL)
            .then((data) =>
            {

                // IF we don't have any documents then the collection doesn't exist
                // so we create it!
                if(data.length === 0)
                {
                    this.generateCollectionAndDocument();
                }

                // Otherwise the collection does exist and we assign the returned
                // documents to the public property of locations so this can be
                // iterated through in the component template
                else
                {
                    this.locations = data;
                    console.log(this.locations);
                }
            })
            .catch();
    }


    retrieveCollectionCat() : void
    {
        this._DB.getDocuments2(this._COLL2)
            .then((data) =>
            {

                // IF we don't have any documents then the collection doesn't exist
                // so we create it!
                if(data.length === 0)
                {
                    this.generateCollectionAndDocument();
                }

                // Otherwise the collection does exist and we assign the returned
                // documents to the public property of locations so this can be
                // iterated through in the component template
                else
                {
                    this.locations2 = data;
                    console.log(this.locations2);
                }
            })
            .catch();
    }


    retrieveCollectionProd() : void
    {
        this._DB.getDocuments3(this._COLL3)
            .then((data) =>
            {
                console.log(data[0].id);
                // IF we don't have any documents then the collection doesn't exist
                // so we create it!
                if(data.length === 0)
                {
                    this.generateCollectionAndDocument();
                }

                // Otherwise the collection does exist and we assign the returned
                // documents to the public property of locations so this can be
                // iterated through in the component template
                else
                {
                    this.locations3 = data;
                    console.log(this.locations3);
                }
            })
            .catch();
    }
}

/*Home.html*/
<ion-header>
  <ion-navbar>
    <ion-title>
      Cloud Firestore
    </ion-title>
  </ion-navbar>
</ion-header>

<ion-content padding>
  <ion-list>
    <ion-item *ngFor="let location of locations">
      <h2>{{ location.Nom_du_Magasin }}</h2>
      <p>
        Nom_du_Magasin: {{ location.Nom_du_Magasin }}<br>
        uid_du_Magasin: {{ location.Uid_du_Magasin }}<br>
        id: {{ location.id }}<br>
      </p>
      <ion-list>
        <ion-item *ngFor="let location2 of locations2">
          <h2>{{ location2.Nom_Categorie }}</h2>
          <p>
            Nom_Catégorie: {{ location2.Nom_Categorie }}<br>
            id: {{ location2.id }}<br>
          </p>
          <ion-list>
            <ion-item *ngFor="let location3 of locations3">
             <h2>{{ location3.Nom_Produit }}</h2>
             <p>
               Nom_Produit: {{ location3.Nom_Produit }}<br>
               id: {{ location3.id }}<br>
             </p>
            </ion-item>
          </ion-list>
        </ion-item>
      </ion-list>
    </ion-item>
  </ion-list>
</ion-content>

And the result is :

Again, I can’t put “dynamically” the path to the right category (Look, my products are the same)

Any ideas?

Thank you for reading, Sorry, i’m learning and discovering Mobile Apps … Stay cool :slight_smile:

If now, there is no ideas, I’m gonna try without a database as you suggested! :slight_smile:

1 Like