Проблема, которую я пытаюсь решить, немного сложна. Я пытаюсь создать рекурсивную функцию в 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 ломается все дальше и дальше.
Разве вы не можете запрограммировать весь рекурсивный выбор в одной функции базы данных?
@HeikoTheißen всего за один заход? Я думаю, он должен быть рекурсивным, если он основан на результате предыдущего запроса.
Я думаю, вы можете выразить это с помощью цикла, а не рекурсии.
Современные базы данных SQL поддерживают рекурсивные запросы (with recursive). Вы уверены, что не сможете этим воспользоваться?
@trincot это был мой первый подход, однако некоторые из этих детализаций имели глубину 10 уровней, и SQL Server требовал около 20 минут, чтобы ответить. Если я не ошибаюсь, маршрут nodejs (api) должен быть намного быстрее.
Многое зависит от фактического SQL-запроса и плана выполнения (использует ли он индексы?), но теоретически это должно быть быстрее, чем отправлять новый оператор SQL для каждого набора дочерних элементов, который необходимо снова компилировать на стороне сервера.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Я не могу комментировать, но думаю, что смогу дать некоторую обратную связь. В приведенном вами примере кода я вижу функцию, которая возвращает массив, и этот массив возвращается в исходную функцию. Обычно при написании рекурсивных функций проводится логическая проверка, позволяющая определить, есть ли необходимость продолжать. В данном случае, кажется, этого можно добиться с помощью некоторых незначительных изменений.
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), а затем условие не выполняется. Есть ли обходной путь для этого?
Прошу прощения за то, что не могу ответить на этот вопрос более прямо, но в настоящее время я не очень хорошо разбираюсь в функциях async и await. Я удивлен, что запрос с ожиданием не завершается, прежде чем двигаться дальше. Поскольку на самом деле он не ждет, для решения этой проблемы, вероятно, потребуется обещание.
Я хотел отметить, что, хотя мой ответ был сосредоточен на рекурсивной функции, он не касается зависающего соединения. С такой функцией, вероятно, было бы лучше создать соединение вне функции и передать его, чтобы его можно было закрыть после завершения функции.
Большое спасибо за ваш ответ. Я думаю, теперь это работает. Ценить это
Каждый раз, когда вы вызываете queryDatabase, вы открываете новое соединение sql, даже не закрывая предыдущее, это, вероятно, вызывает у вас проблемы. Для этого вам понадобится использовать пул соединений для управления несколькими соединениями, если вы планируете рекурсивно использовать паутину, и их обязательно нужно закрыть после того, как вы с ними закончите.