Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

converting rdms like instagram to firebase nosql

I am planning to develop production ready hybrid ionic3 mobile application similar to instagram using firebase. I chose firestore nosql for storing data and querying.

I have experience designing schema in RDMS ( ignore second green colored user table ). But I am struggling to design NoSql schema for my application. Below I added RDMS schema that I want to convert it to nosql. rdms table schema

There are several queries I want to make efficiently.

  1. Show list of latest photos in homepage for guest session.
  2. Show list of followers photos followed by the user in homepage.
  3. List photos tagged by "tag"

Simple Sql query for above list

  1. Select * from photo LIMIT=50

How should I approach to convert photo and user table to firestore NoSql OR NoSql in order to query efficiently?

like image 844
omurbek Avatar asked Jul 20 '18 08:07

omurbek


People also ask

What type of NoSQL database is firestore?

Cloud Firestore is a NoSQL, document-oriented database. Unlike a SQL database, there are no tables or rows. Instead, you store data in documents, which are organized into collections. Each document contains a set of key-value pairs.

Is firebase firestore a NoSQL database?

How does it work? Cloud Firestore is a cloud-hosted, NoSQL database that your Apple, Android, and web apps can access directly via native SDKs.

Does Firebase use JSON?

All Firebase Realtime Database data is stored as JSON objects. You can think of the database as a cloud-hosted JSON tree.

Is firebase a Rdbms?

The key differences between Firebase and MySQL: Architecture: Firebase is a NoSQL database that stores and syncs data in real-time (a real-time document store); MySQL is an open-source relational database management system based on the domain-specific language SQL.


1 Answers

Here is a proposal:

One Collection named photos

with photo documents that have:

  • an auto-generated Id
  • a creation field holding a date (i.e. a timestamp)
  • the extra fields like description, url/path, etc.
  • a tags field as an object with key-value pairs like {black: true, cats: true}, see this help doc for the rationale: https://firebase.google.com/docs/firestore/solutions/arrays. The HTML code below shows how to use/query it
  • a sub-collection of comments

One Collection named users

with user documents that have:

  • the Id of the user (i.e. uid from the authentication)
  • a followedUsers object holding the ids of the users followed by the current user {userId1: true, userId2: true}
  • a followedPhotosId object holding the ids of the photos followed by the current user {9HzWzyXmcnBDuhTZKoQw: true, fO0OvzJs9M8p9N0jufte: true}
  • a followedPhotos sub-collection holding the details of the followed photos

The following HTML page shows how to execute the queries you list in your post, as well as some queries reading and writing data: these latest queries should be used in several Cloud Functions dedicated to keeping the followedPhotosId objects and followedPhotos Collections in synch when a user follows a new other user and/or when a user (followed by one or more users) adds or deletes a photo.

<html>

<head>

<!-- Firebase App is always required and must be first -->
<script src="https://www.gstatic.com/firebasejs/5.3.0/firebase-app.js"></script>

<!-- Add additional services that you want to use -->
<script src="https://www.gstatic.com/firebasejs/5.3.0/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/5.3.0/firebase-database.js"></script>
<script src="https://www.gstatic.com/firebasejs/5.3.0/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/5.3.0/firebase-functions.js"></script>


</head>

<body>


<script>
  // Initialize Firebase
  var config = {
    apiKey: "",
    authDomain: "xxxxx.firebaseapp.com",
    databaseURL: "https://xxxx.firebaseio.com",
    projectId: "xxxxxx"
  };

  firebase.initializeApp(config);

  var firestoredb = firebase.firestore();


  firestoredb.collection("photos").orderBy("creation", "desc")
    .get()
    .then(function(querySnapshot) {
        console.log("YOUR QUERY #1");
        querySnapshot.forEach(function(doc) {
            // doc.data() is never undefined for query doc snapshots
            console.log(doc.id, " => ", doc.data());
        });
    })
    .catch(function(error) {
        console.log("Error getting documents: ", error);
    });


  firestoredb.collection("users").doc("user1").collection("followedPhotos")
    .get()
    .then(function(querySnapshot) {
        console.log("YOUR QUERY #2");
        querySnapshot.forEach(function(doc) {
            // doc.data() is never undefined for query doc snapshots
            console.log(doc.id, " => ", doc.data());
        });
    })
    .catch(function(error) {
        console.log("Error getting documents: ", error);
    });


  firestoredb.collection("photos")
    .where('tags.cats', '==', true) //You should create a photo with a "cats" tag
    .get()
    .then(function(querySnapshot) {
        console.log("YOUR QUERY #3");
        querySnapshot.forEach(function(doc) {
            // doc.data() is never undefined for query doc snapshots
            console.log(doc.id, " => ", doc.data());
        });
    })
    .catch(function(error) {
        console.log("Error getting documents: ", error);
    });




  firestoredb.collection("photos").orderBy("creation", "desc").limit(50)
    .get()
    .then(function(querySnapshot) {
        console.log("YOUR QUERY #4, i.e; Select * from photo LIMIT=50");
        querySnapshot.forEach(function(doc) {
            // doc.data() is never undefined for query doc snapshots
            console.log(doc.id, " => ", doc.data());
        });
    })
    .catch(function(error) {
        console.log("Error getting documents: ", error);
    });

  firestoredb.collection("users")
   .where('followedUsers.user2', '==', true)
   .get()
   .then(function(querySnapshot) {
      console.log("Get all the users who follows user2. To use in the Cloud Function");
      querySnapshot.forEach(function(doc) {
        // doc.data() is never undefined for query doc snapshots
          console.log(doc.id, " => ", doc.data());
      });
  })
  .catch(function(error) {
      console.log("Error getting documents: ", error);
  });


   firestoredb.collection("users")
    .where('followedPhotosId.9HzWzyXmcnBDuhTZKoQw', '==', true)
    .get()
    .then(function(querySnapshot) {
        console.log("Get all the users who follow photo with Id 9HzWzyXmcnBDuhTZKoQw. To use in the Cloud Function");
        querySnapshot.forEach(function(doc) {
            // doc.data() is never undefined for query doc snapshots
            console.log(doc.id, " => ", doc.data());
        });
    })
    .catch(function(error) {
        console.log("Error getting documents: ", error);
    });


    firestoredb.collection("users").doc("user1").get().then(function(doc) {
      if (doc.exists) {
          console.log("Update the followedPhotosId object for user1 after a user she/he follows has added a photo with id abcdefghijklmn. To use in the Cloud Function");
          var followedPhotosId = doc.data().followedPhotosId;;
          Object.assign(followedPhotosId, {abcdefghijklmn: true});
      firestoredb.collection("users").doc("user1").set({followedPhotosId: followedPhotosId});
      } else {
        // doc.data() will be undefined in this case
        console.log("No such document!");
      }
    }).catch(function(error) {
      console.log("Error getting document:", error);
    });




</script>


<body>
</html>
like image 95
Renaud Tarnec Avatar answered Sep 22 '22 13:09

Renaud Tarnec