I am working on NodeJS with firebase-admin. I've structured my firebase database like this
user node:
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')
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.
This is my route:
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:
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 ?
---UPDATE---
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);
});
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..
UPDATE 3: PROBLEM SOLVED
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);
});
});
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.