Thomas Smeman
Thomas Smeman

Reputation: 195

Using wildcards in firestore get query

I want to create a cloud function in firebase that gets triggered whenever a user logs in for the first time. The function needs to add the UID from the authentication of the specific user to a specific, already existing document in firestore. The problem is that the UID needs to be added to a document of which I do not know the location. The code I have right now doesn't completely do that, but this is the part where it goes wrong. The database looks like this when simplified

organisations
    [randomly generated id]
        people
            [randomly generated id]  (in here, a specific document needs to be found based on known email 
                                      adress)

There are multiple different organisations and it is unknown to which organisation the user belongs. I thought of using a wildcard, something like the following:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();
console.log('function ready');
//Detect first login from user
//if(firebase.auth.UserCredential.isNewUser()){
if(true){
    //User is logged in for the first time
    //const userID = firebase.auth().currentUser.UID;
    //const userEmail = firebase.auth().currentUser.email;
    const userID = '1234567890';
    const userEmail = '[email protected]';
    //Get email, either personal or work
    console.log('Taking a snapshot...');
    const snapshot = db.collection('organisations/{orgID}/people').get()
        .then(function(querySnapshot) {
            querySnapshot.forEach(function(doc) {
            console.log(doc.data());
        });
    });
}

I commented out some authentication-based lines for testing purposes. I know the code still runs, because hardcoding the orgID does return the right values. Also, looping trough every organisation is not an option, because I need to have the possibility of having a lot of organisations.

A lot of solutions are based on firestore triggers, like onWrite, where you can use wildcards like this. However, I don't think that's possible in this case

The solution to the problem above:

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const db = admin.firestore();

//Add UID to document in DB[FMIS-94]
//Detect first login from user
//if(firebase.auth.UserCredential.isNewUser()){
  if(true){
    //User is logged in for the first time
    //const userID = firebase.auth().currentUser.UID;
    //const userEmail = firebase.auth().currentUser.email;
    const userID = '1234567890';
    const userEmail = '[email protected]';
    var docFound = false;
    //Get email, either personal or work
    console.log('Taking a snapshot...');
    //Test for work email
    const snapshot = db.collectionGroup('people').where('email.work', '==', userEmail).get()
      .then(function(querySnapshot){
        querySnapshot.forEach(function(doc){
          //work email found
          console.log('work email found');
          console.log(doc.data()); 
          docFound = true;
          const organisationID = doc.ref.parent.parent.id;
          writeUID(doc.id, userID, organisationID);  
        });
      });
  
    if(!docFound){
      //Test for personal email
      const snapshot = db.collectionGroup('people').where('email.personal', '==', userEmail).get()
      .then(function(querySnapshot){
        querySnapshot.forEach(function(doc){
          //personal email found
          console.log('personal email found');
          console.log(doc.data()); 
          const organisationID = doc.ref.parent.parent.id;
          writeUID(doc.id, userID, organisationID);  
        });
      });
    }
  }
  async function writeUID(doc, uid, organisationID){ 
    const res = db.collection(`organisations/${organisationID}/people`).doc(doc).set({
      userId: uid
    }, { merge: true });  
  } 

This was exactly what I needed, thanks for all your help everyone!

Upvotes: 3

Views: 1409

Answers (3)

Frank van Puffelen
Frank van Puffelen

Reputation: 599081

I'm not sure I understand you correctly, but if you want to search across all people collections not matter what organizations document they're under, the solution is to use a collection group query for that.

db.collectionGroup('people').get()
    .then(function(querySnapshot) {    
       querySnapshot.forEach(function(doc) {
        console.log("user: "+doc.id+" in organization: "+doc.ref.parent.parent.id);
    });
});

This will return a snapshot across all people collections in your entire Firestore database.

Upvotes: 1

Renaud Tarnec
Renaud Tarnec

Reputation: 83103

It is not possible to trigger a Cloud Function when a user logs in to your frontend application. There is no such trigger among the Firebase Authentication triggers.

If you want to update a document based on some characteristics of the user (uid or email), you can do that from the app, after the user has logged in.

You mention, in your question, "in here, a specific document needs to be found based on known email address". You should first build a query to find this document and then update it, all of that from the app.


Another classical approach is to create, for each user, a specific document which uses the user uid as document ID, for example in a users collection. It is then very easy to identify/find this document, since, as soon the user is logged in you know his uid.

Upvotes: 2

ABHIRAMAREDDY REDDY
ABHIRAMAREDDY REDDY

Reputation: 81

First setup Cloud Functions according to the official Documentation.

Then after setting up create functions like this:

exports.YOURFUNCTIONNAME= functions.firestore
 .document('organisations/[randomly generated id]/people/[randomly generated id]')
 .oncreate(res => {

    const data = res.data();
    const email = data.email;/----Your field name goes here-----/

     /-----------------Then apply your logic here---------/

 )}

This will triggers the function whenever you create the People -> Random ID

Upvotes: 0

Related Questions