我如何在 express 中 return 嵌套的 firebase query/promise?

How can I return a nested firebase query/promise in express?

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

用户节点:

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

userCompanies
|
+--- uid (-27JfjDfBetveYQNfWhosebug)
      |
      +--- companyId (-KnWhosebugF7DezRD0P) : true
      +--- companyId (-MyWhosebugF99ezRD0V) : true
      +--- .......... : true

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

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

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

这是我的路线:

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)        // -27JfjDfBetveYQNfWhosebug
    .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; // -KnWhosebugF7DezRD0P

                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);
});

但是在 res.send 之后我得到了这个结果:

我不知道这是什么问题。推送工作正常。一旦承诺完成,myObj.companies 就会有一个空数组。如何处理这个嵌套查询和 return 一个数组中的所有数据?

---更新---

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

// 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) // -27JfjDfBetveYQNfWhosebug
            .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; // -KnWhosebugF7DezRD0P

            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 获取每个公司,将公司推送到一个数组,然后 return 这个数组回到最后。但是还是空的..

更新 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) // -27JfjDfBetveYQNfWhosebug
            .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; // -KnWhosebugF7DezRD0P

            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 中,然后 return 编辑数组。所以我现在知道了最新的 ID,并且我能够 运行 snap promise 中 foreach 内的 resolve 方法。

据我所知,您很快就会爱上异步编程 101:数据是从 Firebase 异步加载的。当您写入结果时,数据尚未加载。

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

userCompaniesRef            // db.ref('userCompanies')
    .child(user.uid)        // -27JfjDfBetveYQNfWhosebug
    .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; // -KnWhosebugF7DezRD0P

                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
});