Il recupero dei dati da MongoDB provoca l'errore "Impossibile leggere la proprietà 'nome' di null""

Aug 20 2020

Ho cercato di restituire alcune informazioni sugli utenti e di visualizzarle tramite HTML. Ma ricevo l'errore: "Impossibile leggere la proprietà 'nome' di null" errore "Per memorizzare i dati sto usando MongoDB, per il servizio di backend Express e Node.js e per il frontend Angular. Per comunicare tra back e frontend ho delegato quello a HttpClient.La connessione con Mongo funziona bene poiché la mia console riceve tutti i dati ma quando si tratta del lato frontend mi sta dando questo problema.

metodo di classe route-index.js per la connessione con MongoDB

router.get('/tasks', async (req, res) => {
let MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";
res.json([
    MongoClient.connect(url, function(err, db) {
        if (err) throw err;
        var dbo = db.db('angular-auth');
        dbo.collection('users').find({}).toArray(function(err, result) {
            if (err) throw err;
            console.log(result);
            //db.close;
         });
      })
   ])
 });

Tasks.service.ts metodo di classe per la restituzione dei dati al frontend

getTasks() {
return this.httpClient.get<any>(this.URL + '/tasks');
}

private-tasks.component.ts class ngOnInit() metodo che suppone di ottenere e sottoscrivere i dati

ngOnInit(): void {
this.tasksService.getTasks()
  .subscribe(
    res => {                             
      console.log(res);    //<===== this line is returning null value!
      this.tasks = res;                  
    },
    err => console.log(err)
  );
}

classe private-tasks.component.html

<ul class="list-group">
 <li class="list-group-item" *ngFor='let task of tasks'>
  {{task.firstname}}
 </li>
</ul>

console.log(res); fornisce un valore nullo, ma all'interno dell'istruzione if/else in realtà non è nullo ... Come sono sicuro che non lo sia ... perché lo stesso metodo mi sta dando l'output nella console. ho provato anche ad aggiungere ? a {{task?.firstname}} in questo modo non ricevo alcun errore ma ancora console.log(res); dà valore nullo.

C'è qualcosa che puoi suggerire su come affrontare questo problema?

Risposte

1 LazarLjubenović Aug 21 2020 at 04:35

Il colpevole è la res.jsonchiamata sul lato back-end. Il lato front-end del codice sembra buono. L'argomento della chiamata di funzione dovrebbe essere un oggetto che restituisci dal server al client, ma cosa gli stai dando invece se qualunque MongoClient.connect restituisce -- che probabilmente non è niente (non l'ho mai usato quindi non posso esserne sicuro).

Il punto in cui chiami console.logè all'interno della funzione di callback più interna. Al momento dell'esecuzione di questo pezzo di codice, il database ha risposto e la risposta è pronta per essere inviata al client. Ma si tenta di inviare i dati al client prima che venga eseguito questo callback.

Quindi l'approccio corretto consiste nell'inserire res.jsonall'interno del callback più interno, che viene eseguito quando i dati sono disponibili.

MongoClient.connect(url, function(err, db) {
  if (err) throw err;
  var dbo = db.db('angular-auth');
  dbo.collection('users').find({}).toArray(function(err, result) {
    if (err) throw err;
    console.log(result);
    res.json(result); // <-- res.json goes inside, after data is available
  });
});
Jexon Aug 20 2020 at 02:28

Sembra un problema di Async, ecco cosa puoi provare nel tuo file service.ts:

  1. Dovrai disporre di una sorta di modello mongo per contenere i dati. Per esempio:
 private tasks:TaskModel[] = []
  1. Oltre a un modello, vorrai avere un soggetto che dovrai importare da rxjs.
import {Subject} from 'rxjs';

e

private taskUpdated = new Subject<taskModel>[](); //create a new subject of type taskModel that you will add to
  1. L'ultimo bit da aggiornare nel tuo file service.ts sarebbe questo:
getTasks(){
   this.httpClient.get<any>(this.URL + '/tasks')
   .subscribe((taskData)=> {
       this.taskNotes = taskData;
       this.taskUpdated.next([...this.taskNotes])//adding in taskNotes
})

getTasksUpdatedAsListener(){
   return this.taskUpdated.asObservable();//observable that you will subscribe to in component.ts
}
  1. Quindi nel tuo file component.ts creerai un altro oggetto di sottoscrizione e cambierai il tuo codice in questo:
//subscription that needs to be created
private sub:Subscription;



ngOnInit(): void {
    this.tasksService.getTasks()//this needs to go first. It will get data in the service file

    this.sub = this.taskService.getTasksUpdatedAsListener()
        .subscribe((data TaskModel[])=> {
           console.log(data);//you should see the data come in as json
        })


}

Fammi sapere come va!