I'm trying to loop through a /users path and join it to my auth().listUsers result however this code:
https://github.com/QuantumInformation/svelte-fullstack-starter/blob/master/firebase_specific/functions/src/users.ts#L32
export async function getSomeUsers(amount: number) {
try {
const listUsersResult = await admin.auth().listUsers(amount)
const parsedUsers = listUsersResult.users.map(stripUserSensitiveInfo).map(async user => {
console.log("try read_______________" + user.uid)
let userProfileSnapshot = await admin
.database()
.ref("users/" + user.uid)
.once("value")
console.log("end try read_______________" + user.uid)
return { ...user, userProfileSnapshot }
})
return parsedUsers
} catch (error) {
console.error("Error listing users:", error)
throw new Error("Error users" + error)
}
}
gives this error
Converting circular structure to JSON at JSON.stringify () at stringify
but this code works fine
export async function getSomeUsers(amount: number) {
try {
const listUsersResult = await admin.auth().listUsers(amount)
const parsedUsers = listUsersResult.users.map(stripUserSensitiveInfo).map( user => {
return 1
})
return parsedUsers
} catch (error) {
console.error("Error listing users:", error)
throw new Error("Error users" + error)
}
}
The problem is within the embedded async calls in the map
operator
In order to make it work, you would need to either wait for each iteration, which would also be VERY inefficient. This is because for every additional query the time taken increases Linearly.
My proposal is to convert the entire logic in a way that is scalable. This is fortunately the case with your listAllUsers()
function that returns all the results on one call
export async function getSomeUsers(amount: number) {
try {
/**
* fetch all the users with the provided limit
*/
const allUsers = await admin.auth().listUsers(amount)
/**
* loop through the returned values and create a promise to fetch
* Each of their document
*/
const listUsersResult = allUsers.users.map(user => {
return admin
.database()
.ref("users/" + user.uid)
.once("value")
})
/**
* When all the user documents have been fetched, iterare through them and deduce their values
*/
const parsedUsers = await Promise.all(listUsersResult).then(docSnashots => {
return docSnashots.map(snapshot => {
console.log("end try read_______________" + snapshot.val())
/**
* The records need to be matched with the original values
*/
const originalUserData = allUsers.users.find(u => u.uid === snapshot.key)
return { ...originalUserData, ...snapshot.val() }
})
})
return parsedUsers
} catch (error) {
console.error("Error listing users:", error)
throw new Error("Error users" + error)
}
}
NOTE this method is more compute intensive because of the loops, but more time efficient since every read operation is independent of the other. It can be modified for situations where you're sure the read operations will always take a very short time and (Maybe) would be more resource efficient than the computation of the loops
Based on your 2nd code snippet, i think there is an issue in async call. Did you try whether the async inside the map is working as expected ?. Try like this and check.
let parsedUsers = [];
const userList = listUsersResult.users.map(stripUserSensitiveInfo);
for (const user of userList) {
try {
let userProfileSnapshot = await admin
.database()
.ref("users/" + user.uid)
.once("value")
parsedUsers.push({...user, userProfileSnapshot});
} catch (error) {
console.error('Error on API', error);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With