Firebase get request returning empty array? - javascript

I believe it may just be an error in my logic, but i'm not sure where the problem is exactly and I am looking for help debugging. I am using Firebase Cloud Firestore. I am trying to query through my "follows" collection to return all data where the key "senderHandle" is equal to the params handle and then push that data to the empty array followData. Then, loop through each followData and make a document query call to the "posts" collection. Then, loop through each of the returned documents from the "posts" collection and push each data to the empty array "posts".
When I try to return the posts array though it returns empty. My overall goal is to get all of the users the params handle follows, loop through each user to get their posts, and then push their posts into an empty array.
Functions code:
// fetch home-specific posts (of users following)
exports.getHomePosts = (req, res) => {
let posts = [];
let followData = [];
// get following users
const followDocument = db
.collection("follows")
.where("senderHandle", "==", req.params.handle);
followDocument
.get()
.then((data) => {
if (data.query.size == 0) {
return res.status(400).json({ error: "Not following any users" });
} else {
data.forEach((doc) => {
followData.push(doc.data());
});
}
})
.then(() => {
followData.forEach((follow) => {
db.collection("posts")
.where("userHandle", "==", follow.receiverHandle)
.where("location", "==", "explore")
.get()
.then((data) => {
data.forEach((doc) => {
posts.push({
postId: doc.id,
body: doc.data().body,
userHandle: doc.data().userHandle,
createdAt: doc.data().createdAt,
commentCount: doc.data().commentCount,
likeCount: doc.data().likeCount,
userImage: doc.data().userImage,
});
});
});
});
return res.json(posts);
})
.catch((err) => {
res.status(500).json({ error: err.message });
});
};
followData returned:
[
{
"receiverHandle": "John Doe",
"senderHandle": "bear"
},
{
"senderHandle": "bear",
"receiverHandle": "Yikies"
},
{
"receiverHandle": "bear",
"senderHandle": "bear"
},
{
"receiverHandle": "anon",
"senderHandle": "bear"
},
{
"senderHandle": "bear",
"receiverHandle": "BigYikes"
}
]

There are multiple issues with this code.
You are not waiting promise to be resolved.
Multiple returns statements
You would not create global arrays like posts and followData[you can return in then for next callback]
Code:
// fetch home-specific posts (of users following)
exports.getHomePosts = (req, res) => {
const followDocument = db
.collection("follows")
.where("senderHandle", "==", req.params.handle);
followDocument
.get()
.then((data) => {
if (data.query.size == 0) {
throw new Error("NOT_FOUND");
} else {
return data.map((doc) => doc.data());
}
})
.then((followData) => {
const promises = followData.map((follow) => {
return db
.collection("posts")
.where("userHandle", "==", follow.receiverHandle)
.where("location", "==", "explore")
.get();
});
Promise.all(promises).then((results) => {
const posts = results
.map((data) => {
return data.map((doc) => ({
postId: doc.id,
body: doc.data().body,
userHandle: doc.data().userHandle,
createdAt: doc.data().createdAt,
commentCount: doc.data().commentCount,
likeCount: doc.data().likeCount,
userImage: doc.data().userImage,
}));
})
.flat();
return res.json(posts);
});
})
.catch((err) => {
if (err.message === "NOT_FOUND") {
return res.status(400).json({ error: "Not following any users" });
}
res.status(500).json({ error: err.message });
});
};

Related

How to make your code wait for execution of loop

Following is my getUser function
const getUsers = async (req, res) => {
try {
ddb.get({
TableName: "Tablename",
Key: { Username: req.query.username }
},(err,user) => {
if(err || Object.keys(user).length === 0) {
return res.status(404).json("Something went wrong")
} else {
const userSociety = Object.keys(user.Item.Societies)[0]
ddb.get({
TableName: "Tablename",
Key: { SocietyCode: userSociety }
},(err, society) => {
if(err || Object.keys(society).length === 0) {
return res.status(400).json({ message: "Could not fetch society members" })
} else {
const users = Object.keys(society.Item.SocietyMembers)
const usersData = []
users.forEach(async u => {
ddb.get({
TableName: "TestMyMohallaUsers",
Key: { Username: u }
},async (err,user) => {
if(err || Object.keys(user).length === 0) {
} else usersData.push({
Username: user.Item.Username,
Firstname: user.Item.Name
})
})
})
return res.status(200).json({ message: "Data detched successfully", Users: usersData })
}
})
}
})
} catch (error) {
return res.status(500).json({ error: "Internal Server Error" })
}
}
I want to wait for the execution of forEach and then send back the data via return statement but as of now the return statement gives empty array of users.
Clearly my code in not waiting for the execution of forEach and then returning the data. How can I do that someone help me?
Edit: ddb is an instance of DynamoDB
You'll have a better time if you
use the DynamoDB Promise API instead of a pyramid of callbacks
refactor your code to a couple of functions
Finally, awaiting for all user fetches to complete requires Promise.all for all of those promises.
async function getUser(ddb, username) {
const user = await ddb
.get({
TableName: "TestMyMohallaUsers",
Key: { Username: username },
})
.promise();
if (!user.Item) {
throw new Error(`User ${username} not found`);
}
return user.Item;
}
async function getSociety(ddb, societyCode) {
const society = await ddb
.get({
TableName: "Tablename",
Key: { SocietyCode: societyCode },
})
.promise();
if (!society.Item) {
throw new Error(`Society ${societyCode} not found`);
}
return society.Item;
}
const getUsers = async (req, res) => {
try {
const user = await getUser(ddb, req.params.username);
const userSocietyCode = Object.keys(user.Societies)[0];
const society = await getSociety(ddb, userSocietyCode);
const societyUsers = Object.keys(society.SocietyMembers);
const usersData = await Promise.all(
societyUsers.map(async (member) => {
const user = await getUser(ddb, member);
return {
Username: user.Username,
Firstname: user.Name,
};
}),
);
return res
.status(200)
.json({
message: "Data detched successfully",
Users: usersData,
});
} catch (e) {
return res
.status(400)
.json({ message: `Could not fetch information: ${e}` });
}
};

How to parse part of .then() as a other function

I've got a part of code which repeats few times in my code: The function:
exports.getCategoryProducts = (req, res) => {
db.collection("products")
.where("category", "==", req.params.category)
.limit(10)
.get()
//duplicate code starts
.then((data) => {
let products = [];
data.forEach((doc) => {
products.push({
id: doc.id,
title: doc.data().title,
category: doc.data().category,
description: doc.data().description,
image: doc.data().image,
price: doc.data().price,
rating: doc.data().rating,
});
});
return res.status(200).json(products);
})
.catch((err) => {
console.log(err);
return res.status(500).json({
message: "Something went wrong, please try again later",
});
});
//duplicate code ends
};
How can I extract the part I've marked and use it as a function in other API requests?
Create a handler which receives the data as parameter and returns the transformed data
function dataHandler(data) {
return data.map(doc => ({
id: doc.id,
title: doc.data().title,
category: doc.data().category,
description: doc.data().description,
image: doc.data().image,
price: doc.data().price,
rating: doc.data().rating,
}));
}
function getCategoryProducts((req, res) => {
db.collection("products")
.where("category", "==", req.params.category)
.limit(10)
.get()
.then(data => dataHandler(data))
.then(products => {
res.status(200).json(products);
})
.catch(e => {...});
}
And if this code is always called in the context of an express handler, you can even pass res to the dataHandler and if you are always returning the same error, you could also create an standard errorHandler
function dataHandler(data, res) {
res.status(200).json(data.map(doc => {
let dd = doc.data();
return {
id: doc.id,
title: dd.title,
category: dd.category,
description: dd.description,
image: dd.image,
price: dd.price,
rating: dd.rating,
}
}));
}
function errorHandler(err, res) {
console.log(err);
res.status(500).json({
message: "Something went wrong, please try again later",
});
}
function getCategoryProducts((req, res) => {
db.collection("products")
.where("category", "==", req.params.category)
.limit(10)
.get()
.then(data => dataHandler(data, res))
.catch(e => errorHandler(e, res));
}

How to call function after map function done

nodejs response returning null array.
how to return a response after map function done
var follow = [];
User.findOne(
{ _id: id },
).then(user => {
user.following.map(results => {
User.find({ _id: results.user })
.exec()
.then(res => {
follow.push(res);
});
});
res.json({
status: true,
follow // returning null array
});
});
};
You need to collect the promises and use Promise.all() to know when they are all done:
User.findOne({ _id: id }).then(user => {
let promises = user.following.map(results => {
return User.find({ _id: results.user })
.exec()
.then(res => {
return res;
});
});
Promise.all(promises).then(follow => {
res.json({
status: true,
follow // returning null array
});
}).catch(err => {
console.log(err);
res.sendStatus(500);
});
});
Note, there is no reason in your original code to use .map() if you weren't going to return anything from the .map() callback. In my code, I return the promise.

Firebase SnapShot.val() returns null when trying to access data in vuex

I'm Creating an Application where student, staff and non-teaching staff can access.
my Form Data looks like this:
formData: {
name: "",
email: "",
password: "",
select: null
},
options: ["Student", "Staff", "Non-Teaching Staff"],
Of course in Vuex store i can register user with:
registerUsers({}, payload) {
firebaseAuth.createUserWithEmailAndPassword(payload.email, payload.password)
.then(res => {
const userId = firebaseAuth.currentUser.uid;
console.log(res)
Notify.create({
message: 'Regsitration Successful!.',
color: 'primary',
classes: 'quick'
})
//set student
firebaseDb.ref(`users/'${userId}`).set({
name: payload.name,
email: payload.email,
select: payload.select
});
})
.catch(err => {
console.log(err)
Notify.create({
message: `${err.message}`,
classes: 'quick',
color: 'negative'
})
})
I can also loginUsers with:
loginUsers({}, payload) {
firebaseAuth.signInWithEmailAndPassword(payload.email, payload.password)
.then(res => {
console.log(res);
Notify.create({
message: 'Success!',
classes: 'quick',
color: 'positive'
})
})
.catch(err => {
console.log();
Notify.create({
message: `${err.message}`,
classes: 'quick',
color: 'negative'
})
})
},
The Probems comes from this :
handleAuthStateChange() {
firebaseAuth.onAuthStateChanged(user => {
if (user) {
//set Student
const studentId = firebaseAuth.currentUser.uid;
console.log(studentId)
firebaseDb.ref(`users/${studentId}`).once('value', snapshot => {
console.log(snapshot.val())
})
}
})
},
The Snapshot.val() return null in the console.
What i'm i writing wrong please.
It seems that, by calling firebaseDb.ref(`users/'${userId}`).set({...}) you are creating your user under a node
users/'userId
with a single quote (').
And you try to read the node
users/userId
which does not exists, if the assumption that you mistakenly added a single quote is right.
In addition note that you don't need to do
firebaseAuth.createUserWithEmailAndPassword(payload.email, payload.password)
.then(res => {
const userId = firebaseAuth.currentUser.uid;
//...
because createUserWithEmailAndPassword() returns a UserCredential. So you can do:
firebaseAuth.createUserWithEmailAndPassword(payload.email, payload.password)
.then(res => {
const userId = res.user.uid;
//...
and also that you can do:
handleAuthStateChange() {
firebaseAuth.onAuthStateChanged(user => {
if (user) {
const studentId = user.uid;
//......

Facing issue while fetching latest data's in nodejs

I am facing the issue while fetching the latest data from MongoDB. every 3 hours I am pushing the data to the MongoDB when I fetch the latest data's I am facing an issue.
Here is the Schema
var abc = new Schema({
item_name: String,
uploadedDate: String, //"6-29-2019"
date : Date
});
Fetch the latest data's
req.body.uploadedDate = "7-2-2019" String
router.post('/todayList', (req, res, next) => {
abc.find({ "uploadedDate": { "$eq": req.body.uploadedDate} })
.then(product => {
let final = funct.duplicate(product, 'item_name'); here i am filter duplicate object
var result = [];
final.forEach(comp => {
abc.find({item_name": comp.item_name, "uploadedDate": { "$eq":
req.body.uploadedDate} }) // here i am fetching the latest uploaded data based on the item_name and pushing to the 'result'
.sort({"date":-1})
.limit(1)
.exec((err, docs) => {
console.log(docs); //i am getting the latest data here
result.push(docs);
});
})
//but here the value of 'result' is empty array
res.status(200).json({
data: result
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
});
I am not able to find why it's giving an empty array. please help me with this
The code inside the for loop is asynchronous.
Therefore, the response is sent with an empty result, before the queries in the for loop are done running.
You should make the code wait for the queries to finish running before sending the response.
router.post('/todayList', (req, res, next) => {
abc
.find({ uploadedDate: { $eq: req.body.uploadedDate } })
.then(product => {
let final = funct.duplicate(product, 'item_name')
var promises = []
final.forEach((err, documents) => {
promises.push(
new Promise((resolve, reject) => {
if (err) return reject(err)
abc
.find({ item_name: comp.item_name, uploadedDate: { $eq: req.body.uploadedDate } })
.sort({ date: -1 })
.limit(1)
.exec((err, docs) => {
if (err) return reject(err)
resolve(docs)
})
})
)
})
Promise.all(promises).then(result => {
res.status(200).json({
data: result
})
})
})
.catch(err => {
console.log(err)
res.status(500).json({
error: err
})
})
})

Categories

Resources