3

When I use firebase.firestore() on client-side, the following function works well and managed to find the document:

With firebase.firestore()

function getUserProfile(email, returnDoc) {
    var db = firebase.firestore();
    var docRef = db.collection("Users").doc(email);

    docRef.get().then(function (doc) {
        if (doc.exists) {
            returnDoc(undefined, doc);
        } else {
            returnDoc("User not found.", doc);
        }
    }).catch(function (error) {
        returnDoc("Error getting user.", doc);
    });
};

On index.js

getUserProfile(user.email, function (err, userProfile) {
   if (!err) {
      $scope.firstName = userProfile.get("FirstName");
      $scope.lastName = userProfile.get("LastName");
      $scope.email = userProfile.get("Email");
      $scope.$apply();
   } else {
      alert(err);
    };
});

But when I tried to create another similar function using firebase-admin, the following function can't find the document with the same email argument:

In db.js With admin.firestore()

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

let db = admin.firestore();

function getUserData(email, returnDoc) {
    console.log(`imtp-db.getUserData: ${email}`); // email data is correct and exist in database.

    let docRef = db.collection("Users").doc(email);

    return docRef.get().then(function (doc) {
        console.log(`doc.exists: ${doc.exists}`); // doc.exists: false here.
        if (doc.exists) {
            console.log("Document data:", doc.data());

            return returnDoc(undefined, doc);
        } else {
            return returnDoc("User not found.", doc);
        };
    }).catch(function (error) {
        return returnDoc("Error getting user.", doc);
    });
};

exports.getUserData = getUserData;

In Cloud Function:

const functions = require('firebase-functions');
const db = require("./middleware/db.js");

exports.getUserProfile = functions.https.onCall((data, context) => {
    var userProfile = undefined;
    console.log(`data.email = ${data.email}`);
    return db.getUserData(data.email, function (err, userDoc) {
        console.log(`exports.getUserProfile.err = ${err}`);
        if (!err) {
            userProfile = userDoc.data();
            return {
                error: err,
                returnData: userProfile
            };
        } else {
            return {
                error: err,
                returnData: userProfile
            };
        };
    });
});

Everything works well in the above function without errors except that the doc.exists always evaluated to false and always return "User not found.", why? Anything that I've done wrong in the second version of my code? Thanks!

NOTE: I'm running all emulators: firebase emulators:start

Antonio Ooi
  • 1,601
  • 1
  • 18
  • 32

2 Answers2

4

In reference to this post, apparently, the answer is simple: The local Firestore Emulator has NO DATA. This can be easily proven with the following approach based on the exact same code in the question:

Start all emulators except Firestore Emulator:

  1. firebase serve --only hosting
  2. firebase emulators:start --only functions

Now the document is accessible and doc.exists == true:

enter image description here

Without starting the Firestore Emulator, the code will be forced to access the production server with data. Of course, this is not recommended, especially when you're on Blaze Plan. Hence, as given in the above link, we should setup the test data locally before using Firestore Emulator.

As for the reason why the client-side firebase.firestore() was able to access the data, this is because the Firestore Emulator runs on port different than the hosting. So the firebase.firestore() that was being executed in index.js at the web client side was using localhost:5000, bypassing the Firestore Emulator and went straight to the production server. To resolve this issue, this Firebase Documentation could be the solution (but not yet tested):

// Initialize your Web app as described in the Get started for Web
// firebaseApp previously initialized using firebase.initializeApp().
var db = firebaseApp.firestore();
if (location.hostname === "localhost") {
  db.settings({
    host: "localhost:8080",
    ssl: false
  });
}
Antonio Ooi
  • 1,601
  • 1
  • 18
  • 32
0

When you use an emulator, Firebase would not fetch from the actual Firestore database. It fetches from the Firestore emulator, which you can access with firebase emulator ui, to manage data there. Firestore emulator is different from your actual firestore database.

if you run firebase emulators:start you can view the url to access the emulator ui enter image description here

Dennis Kozevnikoff
  • 2,078
  • 3
  • 19
  • 29
Bharat Varma
  • 154
  • 1
  • 6