如何在Express中返回嵌套的Firebase查询/承诺? [英] How can I return a nested firebase query/promise in express?

查看:69
本文介绍了如何在Express中返回嵌套的Firebase查询/承诺?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用firebase-admin开发NodeJS.我已经像这样构建了Firebase数据库

I am working on NodeJS with firebase-admin. I've structured my firebase database like this

用户节点:

user
|
+--- uid (-27JfjDfBetveYQNfStackOverFlow)
      |
      +-- firstname
      +-- lastname
      +-- mainCompanyId: ''
      +-- ....

userCompanies
|
+--- uid (-27JfjDfBetveYQNfStackOverFlow)
      |
      +--- companyId (-KnStackOverFlowF7DezRD0P) : true
      +--- companyId (-MyStackOverFlowF99ezRD0V) : true
      +--- .......... : true

companies
| 
+--- companyId (-KnStackOverFlowF7DezRD0P)
        |
        +-- name
        +-- createdAt
        +-- updatedAt
        +-- createdBy
        +-- ........

参考已经在服务器上全局定义:

The refs are already defined globally on the server:

  • companiesRef = db.ref('companies')
  • usersRef = db.ref('users')
  • userCompaniesRef = db.ref('userCompanies')

我想做的是让与用户相关的所有公司.为了加入数据,我在数据库中创建了节点 userCompanies ,并将companyId保存为键.检索数据后,我将遍历密钥并通过其ID获得公司.在快递中,我创建了一条名为/api/companies 的路线.如果我尝试将结果返回给客户端,则会得到一个空数组.

What I try to do is to get all companies which are related to the user. To join the data I've created the node userCompanies in the database and saved the companyId as a key. Once I am retrieving the data, I loop through the keys and get the company by their id. In express I've created a route called /api/companies. If I try to return the result back to the client I got an empty array.

这是我的路线:

app.get('/api/companies/', function (req, res) {

// getting the current session. The variable 'sess' is stored globally.
sess = req.session;

// get the current user from the session
var user = sess.user;

// get the mainCompanyId from the user
var mainCompanyId = user.companyId;

// prepare object to return it back
var myObj = {
    mainCompany: mainCompanyId, // ignore. Just a property to see users first created company
    companies: [], // this is the important property/array where I want to store all the companies
    someOtherProperties: true, // ignore
    ..... : .....
};

userCompaniesRef            // db.ref('userCompanies')
    .child(user.uid)        // -27JfjDfBetveYQNfStackOverFlow
    .once('value', function (userCompaniesSnap) {

        // get all companies which are related to the user
        var userCompaniesGroupList = userCompaniesSnap;

        // check if user has companies
        if (userCompaniesGroupList !== null) {

            // loop through all companies and get the companyId by Key
            userCompaniesGroupList.forEach(userCompaniesGroupListSnap => {

                var companyId = userCompaniesGroupListSnap.key; // -KnStackOverFlowF7DezRD0P

                companiesRef // db.ref('companies')
                    .child(companyId)
                    .once('value', companySnap => {

                        // get the current company
                        var company = companySnap.val();

                        // push it to the prepared object
                        myObj.companies.push(company);

                    }); // companiesRef.once('value)

            }); // userCompaniesGroupList.forEach

        } // if userCompaniesGroupList !== null

    }); // query userCompaniesRef

    res.status(200).send(myObj);
});

但是在重新发送后,我得到了这个结果:

But after res.send I get this result:

我不知道这是什么问题.推送工作正常.兑现承诺后, myObj.companies 将有一个空数组.一个嵌套查询如何处理并在一个数组中返回所有数据?

I don't know what here is the problem. The push is working fine. Once the promise is done, myObj.companies has an empty array. How can a handle this nested queries and return all data in one array ?

---更新---

我已经尝试过诺言.还是一样,我得到了一个空数组.这是代码:

I've tried with promises. Still the same, I get an empty array back. Here is the code:

// prepare object to return it back
var myObj = {
    mainCompany: mainCompanyId,
    companies: []
};

var getCompanies = function () {
    return new Promise(function (resolve, reject) {

        userCompaniesRef // db.ref('userCompanies')
            .child(user.uid) // -27JfjDfBetveYQNfStackOverFlow
            .once('value', function (userCompaniesSnap) {

                if (userCompaniesSnap.val() !== null)
                    resolve(userCompaniesSnap);

            });
    });
}

var getCompaniesByList = function (companyList) {
    var companyListArray = [];
    return new Promise(function (resolve, reject) {

        // loop through all companies and get the companyId by Key
        companyList.forEach(userCompaniesGroupListSnap => {

            var companyId = userCompaniesGroupListSnap.key; // -KnStackOverFlowF7DezRD0P

            companiesRef // db.ref('companies')
                .child(companyId)
                .once('value', companySnap => {

                    // get the current company
                    var company = companySnap.val();

                    // push it to the prepared object
                    companyListArray.push(company);

                  //  updatedObjectFinal.push(myObj);

                }); // companiesRef.once('value)

        }); // userCompaniesGroupList.forEach
        resolve(companyListArray);
    });
}

getCompanies().then(function (compList) {
    console.log('compList:', compList.val());
    return getCompaniesByList(compList); // compList has the data. 
}).then(function (endResult) {

    console.log('endResult: ', endResult); // endResult is empty again..

    res.status(200).send(endResult);
});

在这种情况下,我尝试通过用户ID获取所有公司.然后,我尝试将此列表传递给下一个承诺,以按ID来获得每个公司的名称,将公司推送到一个数组,最后将该数组返回.但是仍然是空的..

In this case I've tried to get all companies by user id. Then I tried to pass this list to the next promise to get each company by their ID, push the company to an array and return this array back on the end. But is still empty..

更新3:问题已解决

app.get('/api/companies/', function (req, res) {

// getting the current session
sess = req.session;

// save the user
var user = sess.user;
var userId = user.uid;

var getCompanies = function () {
    return new Promise(function (resolve, reject) {

        userCompaniesRef // db.ref('userCompanies')
            .child(userId) // -27JfjDfBetveYQNfStackOverFlow
            .once('value', function (userCompaniesSnap) {

                // prepare an array
                var companies = [];

                if (userCompaniesSnap.val() !== null) {

                    // loop through the keys and save the ids
                    userCompaniesSnap.forEach(function (companyItem) {
                        // console.log('companyIte,', companyItem.key);
                        companies.push(companyItem.key);
                    });

                    // get the latest item of the array to get the latest key
                    var latestCompanyId = companies[companies.length - 1]

                    // prepare optional object to resolve
                    var finalCompaniesList = {
                        companies: companies,
                        lastCompanyId: latestCompanyId
                    }

                    resolve(finalCompaniesList);

                }

            });
    });
}

var getCompaniesByList = function (companyArray) {

    var companyListArray = [];
    return new Promise(function (resolve, reject) {

        // loop through all companies and get the companyId by Key
        companyArray.companies.forEach(userCompaniesGroupList => {

            var companyId = userCompaniesGroupList; // -KnStackOverFlowF7DezRD0P

            var companyTest = companiesRef // db.ref('companies')
                .child(companyId)
                .once('value', companySnap => {

                    // get the current company
                    var company = companySnap.val();

                    // push it to the prepared object
                    companyListArray.push(company);

                    if (company.id === companyArray.lastCompanyId)
                        resolve(companyListArray); // I am resolving here now the data. 

                }); // companiesRef.once('value)

        }); // userCompaniesGroupList.forEach

    });
}

getCompanies().then(function (compList) {
    return getCompaniesByList(compList);
}).then(function (endResult) {
    res.status(200).send(endResult);
});

});

非常感谢弗兰克!我找到了解决我问题的方法.我现在要做的是,在 getCompanies 中,我运行了一个forEach以用ID预填充数组,并获取数组中的最新companyId.取得最新的ID后,便创建了一个自定义对象,并将最新的ID保存在 latestCompanyId 中,并将数组返回了.因此,我现在知道了最新的ID,并且能够在snap promise中的foreach中运行 resolve 方法.

Big thanks to Frank! I've found a solution for my problem. What I have done now is, in getCompanies I've run a forEach to pre-fill an array with the ids and to get the latest companyId in the array. Once I got the latest id, I've created a custom object and saved the latest id in latestCompanyId and returned the array back. So I know now the latest id and I was able to run the resolve method inside the foreach in the snap promise.

推荐答案

据我所见,您很快就陷入异步编程101的问题:数据是从Firebase异步加载的.当您写入结果时,数据尚未加载.

As far as I can quickly see you're falling for async programming 101: data is loaded from Firebase asynchronously. When you write your result, the data hasn't loaded yet.

要解决此问题,请将响应的内容移到所有数据可用时触发的回调中:

To solve this, move the writing of the response into the callback that fires when all data is available:

userCompaniesRef            // db.ref('userCompanies')
    .child(user.uid)        // -27JfjDfBetveYQNfStackOverFlow
    .once('value', function (userCompaniesSnap) {
        // get all companies which are related to the user
        var userCompaniesGroupList = userCompaniesSnap;

        // check if user has companies
        if (userCompaniesGroupList !== null) {
            // loop through all companies and get the companyId by Key
            userCompaniesGroupList.forEach(userCompaniesGroupListSnap => {

                var companyId = userCompaniesGroupListSnap.key; // -KnStackOverFlowF7DezRD0P

                companiesRef // db.ref('companies')
                    .child(companyId)
                    .once('value', companySnap => {
                        // get the current company
                        var company = companySnap.val();

                        // push it to the prepared object
                        myObj.companies.push(company);

                        // send response to client
                        res.status(200).send(myObj);

                    }); // companiesRef.once('value)
            }); // userCompaniesGroupList.forEach
        } // if userCompaniesGroupList !== null
    }); // query userCompaniesRef
});

这篇关于如何在Express中返回嵌套的Firebase查询/承诺?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆