Создайте рекурсивную функцию в NodeJS

Проблема, которую я пытаюсь решить, немного сложна. Я пытаюсь создать рекурсивную функцию в NodeJS, которая будет запрашивать базу данных для получения результатов. Используя результат из базы данных, ему необходимо вызывать функцию снова и снова.

Например, я делаю запрос к БД, используя параметр 001, в результате получается 002 003 004. 002 может распадаться дальше на 002-A, 002-B, 002-C, тогда как 003 и 004 дальше не распадаются. 002-A может выйти из строя, 002-B может выйти из строя, а 002-C — нет.

По сути, мне нужно снова и снова перебирать результат запроса, добавлять результат в массив и останавливаться, когда результат не получен для ЛЮБОГО из предыдущих номеров лотов в итерации.

let lotArray = [];
let resultArray = [];

async function queryDatabase(lotNumber) {
try {
    let result;
    await sql.connect(config);
    for(lot of lotNumber) {
        result = await sql.query(`SELECT mt.lot AS [MatlLot] from lot mt WHERE job_lot = '` + lot.MatlLot + `'`);
        for(res of result.recordset){
            resultArray.push(res)
        }
    }
    return resultArray;
} catch (err) {
    console.error('Error occurred:', err);
}}

queryDatabase([{MatlLot: "A2400"}])
.then(results => {
    for(res of results){
        lotArray.push(res)
    }
    console.info('Query results:', lotArray);
    queryDatabase(lotArray);
})
.catch(err => {
    console.error('Error:', err);
})

Итак, проблема, с которой я столкнулся, заключается в том, что она опускается на 2 уровня вглубь, а затем перестает повторяться. Я не уверен, чего мне здесь не хватает. Другая проблема, когда я добавляю условие остановки при отсутствии результата из БД, оно останавливается на середине, когда 003, 004 не имеет результатов, а на самом деле 002 ломается все дальше и дальше.

Каждый раз, когда вы вызываете queryDatabase, вы открываете новое соединение sql, даже не закрывая предыдущее, это, вероятно, вызывает у вас проблемы. Для этого вам понадобится использовать пул соединений для управления несколькими соединениями, если вы планируете рекурсивно использовать паутину, и их обязательно нужно закрыть после того, как вы с ними закончите.

jmcgriz 11.04.2024 17:15

Разве вы не можете запрограммировать весь рекурсивный выбор в одной функции базы данных?

Heiko Theißen 11.04.2024 17:30

@HeikoTheißen всего за один заход? Я думаю, он должен быть рекурсивным, если он основан на результате предыдущего запроса.

Sreenath Umagandhi 11.04.2024 17:36

Я думаю, вы можете выразить это с помощью цикла, а не рекурсии.

Heiko Theißen 11.04.2024 17:37

Современные базы данных SQL поддерживают рекурсивные запросы (with recursive). Вы уверены, что не сможете этим воспользоваться?

trincot 11.04.2024 17:40

@trincot это был мой первый подход, однако некоторые из этих детализаций имели глубину 10 уровней, и SQL Server требовал около 20 минут, чтобы ответить. Если я не ошибаюсь, маршрут nodejs (api) должен быть намного быстрее.

Sreenath Umagandhi 11.04.2024 17:46

Многое зависит от фактического SQL-запроса и плана выполнения (использует ли он индексы?), но теоретически это должно быть быстрее, чем отправлять новый оператор SQL для каждого набора дочерних элементов, который необходимо снова компилировать на стороне сервера.

trincot 11.04.2024 17:50
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
7
91
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не могу комментировать, но думаю, что смогу дать некоторую обратную связь. В приведенном вами примере кода я вижу функцию, которая возвращает массив, и этот массив возвращается в исходную функцию. Обычно при написании рекурсивных функций проводится логическая проверка, позволяющая определить, есть ли необходимость продолжать. В данном случае, кажется, этого можно добиться с помощью некоторых незначительных изменений.

async function queryDatabase(lotNumber) {
    try {
        let result;
        // This variable is only used in this function so moved it in 
        let resultArray = [];
        await sql.connect(config);
        for(lot of lotNumber) {
            result = await sql.query(`SELECT mt.lot AS [MatlLot] from lot mt WHERE job_lot = '` + lot.MatlLot + `'`);
            for(res of result.recordset){
                resultArray.push(res)
            }
        }
        // This logic determines if there were results to review and calls this function if there are.
        if (resultArray.length > 0) {
            resultArray = resultArray.concat(queryDatabase(resultArray));
            return resultArray;
        }
        // If there are no additional elements to review EG resultArray.length == 0, return an empty array.
        return [];
    } catch (err) {
        console.error('Error occurred:', err);
    }
}

let finalResult = queryDatabase([{MatlLot: "A2400"}])

У меня нет базы данных для тестирования, и я не могу проверить этот ответ, но надеюсь, что он укажет вам правильное направление.

Большое спасибо за ваш ответ. Я заметил одну вещь: условие, которое вы добавили для проверки того, не является ли resultArray пустым, возвращает false. По сути, прежде чем resultArray будет заполнен данными, код достигает if (resultArray.length > 0), а затем условие не выполняется. Есть ли обходной путь для этого?

Sreenath Umagandhi 11.04.2024 17:45

Прошу прощения за то, что не могу ответить на этот вопрос более прямо, но в настоящее время я не очень хорошо разбираюсь в функциях async и await. Я удивлен, что запрос с ожиданием не завершается, прежде чем двигаться дальше. Поскольку на самом деле он не ждет, для решения этой проблемы, вероятно, потребуется обещание.

5w3rv0 11.04.2024 19:48

Я хотел отметить, что, хотя мой ответ был сосредоточен на рекурсивной функции, он не касается зависающего соединения. С такой функцией, вероятно, было бы лучше создать соединение вне функции и передать его, чтобы его можно было закрыть после завершения функции.

5w3rv0 11.04.2024 19:52

Большое спасибо за ваш ответ. Я думаю, теперь это работает. Ценить это

Sreenath Umagandhi 11.04.2024 19:56

Другие вопросы по теме