简体   繁体   中英

Retrieving data from one firestore document to query another

I have 2 documents in a Firestore collection.

I want to query one document to get the number plate of a user, and with that number plate I want to retrieve the vehicle's data which is stored in the other document.

This is my code:

function get_full_name_by_nplate(nplate){
    var docRef = global_db.collection("customer_data").doc('web-app-vehicle-data');
    docRef.get().then(function(doc) {
        var data = doc.data();
        given_name = data["vehicles"][nplate]["policy_holder_given_name"];
        family_name = data["vehicles"][nplate]["policy_holder_family_name"];
    
        console.log("given name: " + given_name); //this prints correctly! ==> "Jaime"
    
        return given_name + " " + family_name;//this returns undefined
    });
}

//load user data ////driving scores from backend
function loadUserData(user){
    var nplate_list;

    var docRef = global_db.collection("customer_data").doc('web-app-user-data');
    docRef.get().then(function(doc) {
        var data = doc.data();
        user_data = data["users"][user.email];
        nplate_list = user_data["number_plates"];
    
    }).then(function(){

        for(nplate of nplate_list){
        
            get_full_name_by_nplate(nplate).then(full_name => {
                console.log(full_name);//this prints undefined
            });
        }
    });
}

I have read this answer How to return value from firestore database? and I understand that Firestore returns promises so I always have to use .then after a Firestore data retrieval.

Although I am able to print the correct given_name to the console, the function function get_full_name_by_nplate returns undefined

What perhaps isn't working is that I am nesting one promise inside another, but I don't know if it is wrong to nest them, nor how to do it without nesting.

UPDATE

With the answer from @kvetis I have improved the code and now it works. However it still feels wrong, I had to pass nplate_list as a parameter from one .then() to the next one.. I wouldn't want to imagine if I had to pass it on 5 times, and additionally I am still nesting 2 .then() statements which also feels unnatural.

//load user data ////driving scores from backend
function loadUserData(user){



var docRef = global_db.collection("customer_data").doc('web-app-user-data');
    docRef.get().then(function(doc) {
        var data = doc.data();

        global_user_data = data["users"][user.email];
        //console.log(global_user_data["number_plates"]);

        var user_name  = global_user_data["name"] + " " + global_user_data["surname"];
        document.getElementById("welcome_div").innerHTML = user_name;

        var nplate_list = global_user_data["number_plates"];
        
        console.log("these are the nplates: " + nplate_list);
        
        return nplate_list;
    })
    
    .then(function (nplate_list) {
        var docRef = global_db
            .collection("customer_data")
            .doc("web-app-vehicle-data");
        
        docRef.get().then(function(doc) {
            global_vehicle_data = doc.data()["vehicles"];
            
            var cust_dropdown = document.getElementById("cust-search-dropdown");
            dropdown_content = "";
            
            for(nplate of nplate_list){
                //console.log(nplate);
                var full_name = get_full_name_by_nplate(global_vehicle_data, nplate);
                dropdown_content += "<div class=\"cust-dropdown-items\"><a href=\"#\" id=\"" + nplate + "\" class=\"number-plate-links\">" + nplate + " " + full_name + "</a></div>";
            }
            
            cust_dropdown.innerHTML = dropdown_content;
            addListeners();
            
            // If user has only 1 vehicle then pre-load it
            if(nplate_list.length == 1){
                select_customer_express(nplate_list[0]);
            }
        });
    });
}

The problem is that you're probably reading dropdown_content before all the promises complete. You have to wait until all of get_full_name_by_nplate complete.

Unfortunately your code is written so, that you download the vehicle data over and over again.

What would be the best is to chain the two document loads one after other. Otherwise it will be slow and rather costly, since you're getting billed per document get.

function get_full_name_by_nplate(data, nplate) {

    given_name = data["vehicles"][nplate]["policy_holder_given_name"];
    family_name = data["vehicles"][nplate]["policy_holder_family_name"];

    return given_name + " " + family_name;
  
}

//load user data ////driving scores from backend
function loadUserData(user) {
  var nplate_list;

  var docRef = global_db.collection("customer_data").doc("web-app-user-data");
  docRef
    .get()
    .then(function (doc) {
      var data = doc.data();
      user_data = data["users"][user.email];
      nplate_list = user_data["number_plates"];
    })

    .then(function () {
      var docRef = global_db
        .collection("customer_data")
        .doc("web-app-vehicle-data");
      return docRef.get();
    })

    .then(function (doc)  { return doc.data()})

    .then(function (vehicle_data) {
      for (nplate of nplate_list) {
       var full_name=  get_full_name_by_nplate(vehicle_data,nplate);
          dropdown_content +=
            '<div class="cust-dropdown-items"><a href="#" id="' +
            nplate +
            '" class="number-plate-links">' +
            nplate +
            " " +
            full_name +
            "</a></div>";
        
      }
      // now you do things with `dropdown_content`
    });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM