0
votes

I am trying to build a chat with Firebase->firestore with web, and therefore I am trying to make it live with onSnapshot so users will be able to get a message if they have the chat open.

I have structured the noSQL database like this:

I have a collection named Chats, in that collection I have documents, the names of the documents represent a relationship hash between the 2 users which is also stored in my SQL database, My thought is I will use this as the identifier.

enter image description here

In each document, there is a collection named 'conversations' wich will contain all of the chats between the two users.

enter image description here

If I listen on a document that has a specific id inside the first collection 'chats', I will get a log in my console if I change a field like 'timestamp', so that part works.

db.collection('chats').where(firebase.firestore.FieldPath.documentId(), '==', '#randomHASH').onSnapshot((snapshot) => {
    let changes = snapshot.docChanges();
    console.log('CHANGES');
    console.log(changes);

    changes.forEach(change => {
        console.log(change.doc.data());
    })
});

But how do I listen for the collection 'conversations' inside of the targeted document? I would like to get a log every time a new document has been added or edited inside the targeted document

I tried, but that does not seem to be the trick :)

db.collection('chats').where(firebase.firestore.FieldPath.documentId(), '==', '#randomHASH').collection('conversations').onSnapshot((snapshot) => {
    let changes = snapshot.docChanges();
    console.log('CHANGES');
    console.log(changes);

    changes.forEach(change => {
        console.log(change.doc.data());
    })
});

And this is how i initinate Firebase

<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.1.0/firebase-app.js"></script>

<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/7.1.0/firebase-firestore.js"></script>

<!-- TODO: Add SDKs for Firebase products that you want to use
     https://firebase.google.com/docs/web/setup#available-libraries -->
<script src="https://www.gstatic.com/firebasejs/7.1.0/firebase-analytics.js"></script>

<script>
  // Your web app's Firebase configuration
  var firebaseConfig = {
    apiKey: "xxxxxxxxx",
    authDomain: "myapp-xxxxx.firebaseapp.com",
    databaseURL: "https://myapp.firebaseio.com",
    projectId: "myapp-xxxxx",
    storageBucket: "myapp-xxxxx.appspot.com",
    messagingSenderId: "xxxxxxxxx",
    appId: "1:xxxxx:web:xxxx",
    measurementId: "x-xxxxxx"
  };
  // Initialize Firebase
  firebase.initializeApp(firebaseConfig);
  firebase.analytics();
  const db = firebase.firestore();
</script>
1

1 Answers

3
votes

You should simply do:

db.collection('chats').doc('#randomHASH').collection('conversations').onSnapshot((snapshot) => {...});

As explained in the doc, "A DocumentReference can also be used to create a CollectionReference to a subcollection."

Actually, you can chain the collection() and doc() methods, as many time as needed, to get a reference to any doc or (sub-)(sub-)(...)collection


Note that, similarly, in the first case you can do:

db.collection('chats').doc('#randomHASH').onSnapshot((snapshot) => {...});

Now, why is your code working in the first case and not in the second case?

In the first case, by doing db.collection('chats').where(firebase.firestore.FieldPath.documentId(), '==', '#randomHASH') you define a query which does have an onSnapshot() method.

But in the second case you call a collection() method on the same query, while a query does not have such a method.