Простой запрос Firebase дает ошибку: «Преобразование круговой структуры в JSON при JSON .stringify» - PullRequest
4 голосов
/ 16 февраля 2020

Я пытаюсь l oop через путь / users и присоединить его к моему auth (). ListUsers приводит, однако, следующий код:

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

выдает эту ошибку

Преобразование круговой структуры в JSON в JSON .stringify () при stringify

, но этот код работает нормально

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

Ответы [ 5 ]

2 голосов
/ 24 февраля 2020

Проблема заключается во встроенных асинхронных c вызовах в операторе map. Чтобы заставить его работать, вам нужно будет либо подождать каждую итерацию, что также будет ОЧЕНЬ неэффективно. Это связано с тем, что для каждого дополнительного запроса время увеличивается линейно. Мое предложение состоит в том, чтобы преобразовать всю логику c таким образом, чтобы она была масштабируемой. К счастью, это относится к вашей функции listAllUsers(), которая возвращает все результаты за один вызов

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

ПРИМЕЧАНИЕ этот метод требует больше вычислений из-за циклов, но более экономит время поскольку каждая операция чтения не зависит от другой. Его можно изменить в ситуациях, когда вы уверены, что операции чтения всегда будут занимать очень короткое время и (возможно) будут более ресурсоэффективными, чем вычисление циклов

2 голосов
/ 19 февраля 2020

Вы не можете использовать это так. Для вашей второй функции карты он вернет массив обещаний. Таким образом, вам придется выполнить все обещания, а затем использовать Promise.all для их разрешения.

return Promise.all(parsedUsers);
2 голосов
/ 19 февраля 2020

Исходя из вашего второго фрагмента кода, я думаю, что есть проблема в вызове asyn c. Вы пробовали, работает ли asyn c внутри карты, как ожидалось? Попробуйте вот так и проверьте.

    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);
      }
    }
1 голос
/ 25 февраля 2020

Преобразование круговой структуры в JSON при JSON .stringify () при stringify

Эта ошибка вызвана строковой структурой круговой структуры. Круговая структура - это структура, которая имеет атрибут / атрибут глубины, который ссылается на себя.

const a = {}
a.b = a; // this creates a circular structure

Первый Вы должны проверить, создает ли функция stripUserSensitiveInfo круговую структуру. Это возможно потому, что ошибка произошла, когда объект user является результатом функции и возвращается в первом фрагменте.

Second , как указано в этом комментарии { ссылка } , в первом фрагменте переменная parsedUsers фактически содержит массив обещаний вместо массива пользовательских данных. Чтобы разрешить массив обещаний, используйте Promise.all()

const parsedUsers = await Promise.all(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 };  // You might also want to tweak this structure
  }));

Еще один , немного из топи c, предполагая, что admin.database().ref("users/" + user.uid).once("value") - это сетевой вызов, вы Возможно, вы захотите использовать for...of statement вместо карты. Это сделано для того, чтобы приложение не затопляло сетевое соединение, выполняя слишком много сетевых запросов, в зависимости от значения переменной amount.

1 голос
/ 23 февраля 2020

Посмотрел репозиторий github, который вы связали ... не совсем понимает, как вы попадаете в точку

Преобразование круговой структуры в JSON при JSON .stringify () в stringify

Поскольку код

export const listUsers = functions.https.onRequest(async (req, res) => {
    ...
    const data = await getSomeUsers(10)
    res.json(data)
})

в firebase_specific / functions / src / index.ts должен выглядеть как

export const listUsers = functions.https.onRequest(async (req, res) => {
    ...
    const data = await Promise.all(await getSomeUsers(10))
    res.json(data)
})

Или, что еще лучше, @AlbertPinto указал, что return parsedUsers следует изменить на return Promise.all(parsedUsers)

В любом случае, вернуться к сообщению об ошибке:

userProfileSnapshot - это объект DataSnapshot, и, судя по ошибке, имеет циклические ссылки. Поэтому вам, вероятно, следует изменить

return { ...user, userProfileSnapshot }

на

return { ...user, userProfileSnapshot.val() }

или что-то подобное, в зависимости от ваших потребностей

...