2017-07-14 6 views
0

私はfirebase-adminでNodeJSに取り組んでいます。Expressでネストされたfirebaseクエリ/約束を返すにはどうしたらいいですか?

  • companiesRef = db.ref( '会社')
  • :レフリーがすでにサーバーにグローバルに定義されている

    user 
    | 
    +--- uid (-27JfjDfBetveYQNfStackOverFlow) 
         | 
         +-- firstname 
         +-- lastname 
         +-- mainCompanyId: '' 
         +-- .... 
    
    userCompanies 
    | 
    +--- uid (-27JfjDfBetveYQNfStackOverFlow) 
         | 
         +--- companyId (-KnStackOverFlowF7DezRD0P) : true 
         +--- companyId (-MyStackOverFlowF99ezRD0V) : true 
         +--- .......... : true 
    
    companies 
    | 
    +--- companyId (-KnStackOverFlowF7DezRD0P) 
         | 
         +-- name 
         +-- createdAt 
         +-- updatedAt 
         +-- createdBy 
         +-- ........ 
    

    :私はこの

    ユーザノードのように私のfirebaseデータベースを構造化しました

  • usersRef = db.ref( 'ユーザ')
  • userCompaniesRef = db.ref( 'userCompanies')

私がしようとしているのは、に関連するすべての企業を取得することです。データを結合するには、ノードuserCompaniesをデータベースに作成し、companyIdをキーとして保存しました。データを取得すると、キーをループしてIDで会社を取得します。エクスプレスでは/api/companiesというルートを作成しました。結果をクライアントに返そうとすると、空の配列が返されます。

これは私のルートです:

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

しかしres.sendた後、私はこの結果を得る:

Empty Array

私は問題があるここで何を知りません。プッシュは正常に動作しています。約束が完了したら、myObj.companiesに空の配列があります。どのようにこのネストされたクエリを処理し、すべてのデータを1つの配列に返すことができますか?

--- --- UPDATE

私は約束して試してみました。それでも、空の配列が返ってきます。コードは次のとおりです。

この場合、すべての会社をユーザーIDで取得しようとしました。そして、私はこのリストを次の約束に渡して、各企業をIDで取得し、会社をアレイに押し込み、このアレイを最後まで返すことを約束しました。しかし

UPDATE 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を知っていると私はの解決策を実行することができたforeach内のスナップ約束。

+0

最初の推測は以下の通りです。これで問題を解決できない場合は、コードとテキストを[問題を再現するために必要な最小限]に減らすことができますか?(http://stackoverflow.com/help/mcve) –

答えて

0

私はすぐに非同期プログラミングのために落ちてくるのを見ることができます。101:データはFirebaseから非同期にロードされます。結果を書き込むと、データはまだロードされていません。

、この問題を解決する火災、すべてのデータが利用可能であるコールバックへの応答の書き込みを移動するには:

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

ありがとうフランク!私はあなたが私の質問について見てきたことを嬉しく思います。私はfirebaseについての他のトピックであなたの答えに基づいて多くを学んだ。 しかし問題は、すべての企業を返すことができないということです。上記の例のように、「送信後にヘッダーを設定できません」というエラーが表示されます。私はforEachループに入っているからです。私が望むのは、すべての企業を取得し、myObj.companiesにプッシュし、このオブジェクトを戻すことです。 私は私の質問を更新しました、私は約束を試みました。しかし、私は結果を得ることさえできません。私は会社のリストを取得しますが、myObj.companiesの配列はまだ空です。 – Harry

+0

ああ...それは別の問題です: 'send()'を呼び出すと、応答が閉じられます。あなたは書くこと '書き込みを()'を使用する必要がありますhttps://stackoverflow.com/questions/21749590/difference-between-response-send-and-response-write-in-node-js –

+0

私が理解できるように、私がすべき応答を直接foreachに書き込む/プッシュ/保存する代わりに配列を生成し、res.send(myArray)でこれを戻します。 – Harry

関連する問題