Domanda Passare i dati da un backend in nodejs a frontend javascript

jr_sottomajor

Utente Silver
2 Luglio 2017
96
33
4
79
Ultima modifica da un moderatore:
Ciao a tutti sto realizzando una web app che consiste in un quiz.
Sorvolando i dettagli del quiz, faccio uso di servizi azure (in particolare un database sql e di intelligenza artificiale).
Il motivo per cui sto aprendo questa discussione è perché ciò che dovrei fare è abbastanza banale ma mi sta dando problemi.
In pratica in node interrogo il database azure e faccio una select di 10 frasi che mi serviranno per un quiz, che mantengo in un array.
Una volta fatto ciò ho necessità di passare l'array da node (backend) a javascript frontend poichè lì saranno manipolati ed utilizzati.
Questo è il codice del backend:
JavaScript:
const express = require('express');
const app = express();

const { Connection, Request } = require("tedious");

//configurazione per connessione a db (username, password, server ecc.)
const config = {
  authentication: {
    options: {
      userName: "provadb", // update me
      password: "REDACTED" // update me
    },
    type: "default"
  },
  server: "dbprova-server.database.windows.net", // update me
  options: {
    database: "dbprova", //update me
    encrypt: true
  }
};

const connection = new Connection(config);

//array che mantiene dati restituiti dalla query al db
var valore = [];

app.set('view engine', 'html');
app.engine('html', require('ejs').renderFile);
app.use(express.static(__dirname + "/views"));


connection.on("connect", err => {
  if (err) {
    console.error(err.message);
  } else {
    queryDatabase();
  }
});

connection.connect();

//funzione che interroga il database e mantiene dati restituiti nell'array 'valore'
function queryDatabase() {

  // Read all rows from table
  const request = new Request(
    `SELECT top 10 * FROM [dbo].[frasi]
    order by newId()`,
    (err, rowCount) => {
      if (err) {
        console.error(err.message);
      } else {
        console.log(`${rowCount} row(s) returned`);
      }
    }
  );

  request.on("row", columns => {
    columns.forEach(column => {

      valore.push(column.value)
      //console.log("%s\t%s", column.metadata.colName, column.value);
    });
  });

  connection.execSql(request);
}



app.get('/', function(req, res){
  res.sendFile(__dirname + '/views/index.html')
});


//invio dati dal backend al fronted, dove saranno poi manipolati e mostrati a schermo
app.post('/datidb', function(req, res){
  res.json(valore);
});

app.listen(3000, function(){
  console.log('Ok server: 3000');
});

Il punto è che così com'è realizzato la query viene effettuata una singola volta quando il server viene eseguito.
Ho invece necessità di fare la query ogni qualvolta il quiz viene fatto partire così da avere sempre nuove domande/frasi.
La cosa che mi blocca è il abbinare la logica di connessione e query al db con il passaggio dell'array ottenuto al frontend.
Nel codice sopra passo i dati facendo una post(/datidb), ci sono altri modi per passare dati da node a js?
Inoltre non riesco a chiudere la connessione al db.. se aggiungo una .close() la connessione viene chiusa prima ancora di aver preso i dati. Come posso far sì che la connessione si chiuda dopo che i dati sono stati presi (una specie di wait)?

Idealmente vorrei far in modo che ogni volta che l'utente raggiunge '/quiz.html' si faccia la query, si passino i dati al frontend e questi poi siano visibili a schermo.
Una cosa del tipo:
JavaScript:
app.get('/quiz.html', function(req, res){
    //interroga db e ottieni dati
    //passa dati al frontend
    //mostra quiz
});

Come posso fare? Grazie in anticipo
 
Se ho capito bene vuoi eseguire la query ogni qual volta viene chiamata /datidb? In questo caso ti basta aggiungere return valore; alla fine della funzione queryDatabase() e cambiare res.json(valore); con res.json(queryDatabase());.
Io direi che quella chiamata può diventare una get request in quanto il frontend non passa nulla (quiz.html userà un API come fetch per ottenere i dati e mostrarli una volta aperta), poi immagino tu voglia inviare le risposte dell'utente al quiz indietro sul backend, in quel caso ti servirà una post request dove passare il json con le risposte.

Per chiudere la connessione ti direi ad intuito (non so di tedious e so poco di nodejs):
JavaScript:
function queryDatabase() {

  // Read all rows from table
  const request = new Request(
    `SELECT top 10 * FROM [dbo].[frasi]
    order by newId()`,
    (err, rowCount) => {
      if (err) {
        console.error(err.message);
      } else {
        console.log(`${rowCount} row(s) returned`);
      }
    }
  );

  request.on("row", columns => {
    columns.forEach(column => {

      valore.push(column.value)
      //console.log("%s\t%s", column.metadata.colName, column.value);
    });
  });

  request.on("done", (a, b, c) => {
      // chiude solo dopo che ha finito
      connection.close();
  });

  connection.execSql(request);
  return valore;
}
 
Innanzitutto grazie mille per la disponibilità. Ho apportato tutte le modifiche che mi hai suggerito ed ora effettivamente la query viene eseguita ogni volta che faccio partire il quiz.
L'unico problemino è che comunque le domande mostrate a schermo restano sempre le stesse a meno che non faccia ripartire il server.
Non devo inviare le risposte indietro nel backend ma vengono gestite direttamente nel front-end. In parole povere si tratta di un 'quiz' dove vengono mostrate frasi in inglese a schermo e l'utente deve pronunciare ciò che c'è scritto, dopodichè un servizio azure di intelligenza artificiale valuterà la pronuncia e assegnerà un punteggio.
Quindi viene tutto fatto in js front-end.
Vorrei capire come mai le frasi non si aggiornino ma restino sempre le stesse nonostante la query venga ripetuta ad ogni inizio quiz. Questo è il codice front-end:
JavaScript:
const question = document.querySelector('#question');
const choices = Array.from(document.querySelectorAll('.choice-text'));
const progressText = document.querySelector('#progressText');
const scoreText = document.querySelector('#score');
const progressBarFull = document.querySelector('#progressBarFull');

let currentQuestion = {}
let acceptingAnswers = true
let score = 0
let questionCounter = 0
let availableQuestions = []

// subscription key and region for speech services.
const subscriptionKey = '';   //change me
const serviceRegion = '';    //change me
var SpeechSDK;
var recognizer;


$.get('/datidb', function(data){

  const MAX_QUESTIONS = 10

  var questionsIndex = 0

  startQuiz = () =>{
      questionCounter = 0
      score = 0
      availableQuestions = [...data]
      getNewQuestion()
  }

  getNewQuestion = () => {
      if(availableQuestions.length === 0 || questionCounter > MAX_QUESTIONS){
          localStorage.setItem('mostRecentScore', score)

          return window.location.assign('/end.html')
      }
    
      //incrementa contatore domande
      questionCounter++

      //div in alto a sinistra percentuale completamento domande
      progressText.innerText = `Domanda ${questionCounter} di ${MAX_QUESTIONS}`
      progressBarFull.style.width = `${(questionCounter/MAX_QUESTIONS) * 100}%`

      questionsIndex++;

      //sceglie prossima domanda
      currentQuestion = availableQuestions[questionsIndex]
      question.innerText = currentQuestion

      //rimuove dall'array
      availableQuestions.splice(questionsIndex, 1)

      acceptingAnswers = true
  }

  //registra
  let rec = document.querySelector('.rec');
  rec.addEventListener('click', function(){
      //rec.disabled = true;
      verify.disabled = true;

      //creo servizio voce con key e region
      var speechConfig = SpeechSDK.SpeechConfig.fromSubscription(subscriptionKey, serviceRegion);
      var prova = currentQuestion;
    

      var pronunciationAssessmentConfig = new SpeechSDK.PronunciationAssessmentConfig(prova, true);
      
          //lingua inglese
          speechConfig.speechRecognitionLanguage = "en-US";

          //fonte input audio
          var audioConfig = SpeechSDK.AudioConfig.fromDefaultMicrophoneInput();
          recognizer = new SpeechSDK.SpeechRecognizer(speechConfig, audioConfig);

          pronunciationAssessmentConfig.applyTo(recognizer);

          recognizer.recognizeOnceAsync(
              function (result) {
                rec.disabled = true;

                parsedJSON = JSON.parse(result.json);
                punteggio = Math.floor(parseInt(JSON.stringify(parsedJSON.NBest[0].PronunciationAssessment.AccuracyScore)) +
                parseInt(JSON.stringify(parsedJSON.NBest[0].PronunciationAssessment.FluencyScore)) +
                parseInt(JSON.stringify(parsedJSON.NBest[0].PronunciationAssessment.CompletenessScore)) +
                parseInt(JSON.stringify(parsedJSON.NBest[0].PronunciationAssessment.PronScore)));
                incrementScore(punteggio)

                alert("Confidence: " + parsedJSON.NBest[0].Confidence + "\n" +
                  "Accuratezza: "+ parsedJSON.NBest[0].PronunciationAssessment.AccuracyScore + "\n" +
                  "Scioltezza: " + parsedJSON.NBest[0].PronunciationAssessment.FluencyScore + "\n" +
                  "Completezza: " + parsedJSON.NBest[0].PronunciationAssessment.CompletenessScore + "\n" +
                  "Pronuncia: " + parsedJSON.NBest[0].PronunciationAssessment.PronScore);
  
                recognizer.close();
                recognizer = undefined;
                verify.disabled = false;
                document.querySelector(".next").style.visibility = "visible";
              },
              function (err) {
                rec.disabled = false;
                window.console.log(err);
  
                recognizer.close();
                recognizer = undefined;
              });

  });

  //bottone prossima domanda
  let next = document.querySelector('.next');
  next.addEventListener('click', function(){
      getNewQuestion();
      document.querySelector(".next").style.visibility = "hidden";
      rec.disabled = false;
      verify.disabled = false;
  });

  //bottone suggerimento pronuncia
  let verify = document.querySelector(".verify");
  verify.addEventListener('click', function(){


      //creo servizio voce con key e region
      var speechConfig = SpeechSDK.SpeechConfig.fromSubscription(subscriptionKey, serviceRegion);
      synthesizer = new SpeechSDK.SpeechSynthesizer(speechConfig);

      let inputText = currentQuestion

      synthesizer.speakTextAsync(
          inputText,
          function (result) {
            startSpeakTextAsyncButton.disabled = false;
            if (result.reason === SpeechSDK.ResultReason.SynthesizingAudioCompleted) {
              resultDiv.innerHTML += "synthesis finished for [" + inputText + "].\n";
            } else if (result.reason === SpeechSDK.ResultReason.Canceled) {
              resultDiv.innerHTML += "synthesis failed. Error detail: " + result.errorDetails + "\n";
            }
            window.console.log(result);
            synthesizer.close();
            synthesizer = undefined;
          },
          function (err) {
            startSpeakTextAsyncButton.disabled = false;
            resultDiv.innerHTML += "Error: ";
            resultDiv.innerHTML += err;
            resultDiv.innerHTML += "\n";
            window.console.log(err);

            synthesizer.close();
            synthesizer = undefined;
        });

  });

  //bottone per tornare alla home
  let home = document.querySelector(".home");
  home.addEventListener('click', function(){
      //getNewQuestion();
      location.href = "/index.html";
  });

  //incrementa lo score
  incrementScore = num => {
      score += num
      scoreText.innerText = score
  }

  startQuiz()
});

Il problema credo si trovi sicuramente all'inizio, sembra un po' lunghetto ma come puoi vedere sono solo funzioni richiamate al click su uno specifico bottone.
Credi che il problema sia aver messo tutta la logica front-end nella get? Non riesco a capire..
 
Vengono mostrate sempre le stesse perchè la query di selezione è sempre la stessa e sono ordinate sempre allo stesso modo. Dovresti fare un pescaggio pseudo randomico
 
No, neanche se refresho la pagina. Mi da sempre le stesse.
Ma nei log vedo che è stata effettutata una nuova query. Per avere domande diverse devo far ripartire il server
 
JavaScript:
const express = require('express');
const bodyParser = require('body-parser');
const port = process.env.port || 80;
const app = express();

const { Connection, Request } = require("tedious");

//configurazione per connessione a db (username, password, server ecc.)
const config = {
  authentication: {
    options: {
      userName: "", // update me
      password: "" // update me
    },
    type: "default"
  },
  server: "", // update me
  options: {
    database: "", //update me
    encrypt: true
  }
};

const connection = new Connection(config);

//array che mantiene dati restituiti dalla query al db
var valore = [];

app.set('view engine', 'html');
app.engine('html', require('ejs').renderFile);
app.use(express.static(__dirname + "/views"));
app.use(bodyParser.json());


connection.on("connect", err => {
  if (err) {
    console.error(err.message);
  } else {
    queryDatabase();
  }
});

connection.connect();

//funzione che interroga il database e mantiene dati restituiti nell'array 'valore'
function queryDatabase() {

  // Read all rows from table
  const request = new Request(
    `SELECT top 10 * FROM [dbo].[frasi]
    order by newId()`,
    (err, rowCount) => {
      if (err) {
        console.error(err.message);
      } else {
        console.log(`${rowCount} row(s) returned`);
      }
    }
  );

  request.on("row", columns => {
    columns.forEach(column => {

      valore.push(column.value)
      console.log("%s\t%s", column.metadata.colName, column.value);
    });
  });

  request.on("done", function() {
      // chiude solo dopo che ha finito
      connection.close();
 
  });

  connection.execSql(request);
  return valore;
}

app.get('/', function(req, res){
  res.sendFile(__dirname + '/views/index.html')
});

//invio dati dal backend al fronted, dove saranno poi manipolati e mostrati a schermo
app.get('/datidb', function(req, res){
  res.json(queryDatabase());
});


app.listen(port, function(){
  console.log('Ok server: 3000');
});
Messaggio unito automaticamente:

Ho modificato la porta per problemi quando hosto l'app su azure ma non c'entra molto