Marko Malbasic
Marko Malbasic

Reputation: 149

Retrieving data from MongoDB causes "Cannot read property 'firstname' of null" error"

I have been trying to return some users info and to display them trough HTML. But I am getting the error: "Cannot read property 'firstname' of null" error" To store data I am using MongoDB, for the backend service Express and Node.js and for the frontend Angular. To communicate between back and frontend I delegated that to HttpClient. Connection with Mongo works fine since my console receiving all data but when it comes to the frontend side it's giving me this issue.

routes-index.js class method for connection with 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 class method for returning data to frontend

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

private-tasks.component.ts class ngOnInit() method which supposes to get and to subscribe data

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

private-tasks.component.html class

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

console.log(res); gives null value, but within if/else statement it's actually not null... How I am sure that is not... coz the same method is giving me output in the console. I have tried also to add ? to {{task?.firstname}} in that way I am not getting any error but still console.log(res); gives null value.

Is there anything that you can suggest how to approach this problem?

Upvotes: 1

Views: 1764

Answers (3)

AHMET UCAR
AHMET UCAR

Reputation: 1

I had the same problem and deleted the sessions in mongodb, the problem was solved.

Upvotes: 0

Lazar Ljubenović
Lazar Ljubenović

Reputation: 19754

The culprit is the res.json call on the back-end side. The front-end side of the code seems good. The argument of the function call is supposed to be an object that you return from the server to the client, but what you'\re giving it instead if whatever MongoClient.connect returns -- which is probably nothing (I've never used it so I can't be sure).

The place where you call console.log is inside the innermost callback function. At the moment this piece of code runs, the database has responded and the response is ready to be sent to the client. But you attempt to send the data to the client before this callback is run.

So the correct approach is to place res.json inside the innermost callback, which runs when the data is available.

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

Upvotes: 1

Jexon
Jexon

Reputation: 53

This sounds like an Async issue, here is what you can try in your service.ts file:

  1. You will need to have some sort of mongo model to hold the data. For example:
 private tasks:TaskModel[] = []
  1. In addition to a model, you will want to have a subject which you will need to import from rxjs.
import {Subject} from 'rxjs';

and

private taskUpdated = new Subject<taskModel>[](); //create a new subject of type taskModel that you will add to
  1. The last bit to update in your service.ts file would be this:
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. Then in your component.ts file you will create another subscription object and change your code to this:
//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
        })


}

Let me know how it goes!

Upvotes: 0

Related Questions