How to extract only certain properties of json, returning as an observable using rxjs

1.7k Views Asked by At

For example this is the json which I am receiving,

{
    "events": [...
    ],
    "total": 12341,
    "students": [
        {
            "id": 1,
            "first_name": "John",
            "last_name": "Apple"
        },
        {
            "id": 2,
            "first_name": "Bob",
            "last_name": "Banana"
        },
        {
            "id": 3,
            "first_name": "Charles",
            "last_name": "Carrot"
        }
    ]
}

And I want to transform the data to the following form, and return it as an observable

[
    {
        "first_name": "John",
        "last_name": "Apple"
    },
    {
        "first_name": "Bob",
        "last_name": "Banana"
    },
    {
        "first_name": "Charles",
        "last_name": "Carrot"
    }
]

I have tried the following, but it returns undefined.

getStudentsName(): Observable<any> {
    const requestUrl = this.rootURL + `students/`;
    let studentsInfo = this.http.get<any>(requestUrl).pipe(map(o => o.students));
    return studentsInfo.pipe(map(students => {students.first_name, students.last_name}));
  }

returns undefined when subscribing to observable

this.getStudentsInfoService.getStudentsName()
      .subscribe((result) => console.log('here', result));
4

There are 4 best solutions below

10
Hassan On

It looks like it can't find students. Try this :

return studentsInfo.pipe(map(s => { return {
  first_name: s.first_name,
  last_name: s.last_name,
}}));
1
okihnjo On

Here is a short code snippet.

const object = {
    "total": 12341,
    "students": [
        {
            "id": 1,
            "first_name": "John",
            "last_name": "Apple"
        },
        {
            "id": 2,
            "first_name": "Bob",
            "last_name": "Banana"
        },
        {
            "id": 3,
            "first_name": "Charles",
            "last_name": "Carrot"
        }
    ]
}

let arr: any = [];
object.students.forEach(person => arr.push(
    {
        "first_name": person.first_name,
        "last_name": person.last_name
    }))

console.log(arr)


    [LOG]: [{ "first_name": "John", "last_name": "Apple" }, 
{ "first_name": "Bob", "last_name": "Banana" }, { "first_name": "Charles", "last_name": "Carrot" }] 

You can iterate over students with a foreach loop and then create a new json which you then push in your new array

this.http.get<any>(requestUrl).pipe(map(o => o.students.foreach(person => arr.push({
...}));
0
Owen Kelvin On

The Problem

The Problem is with your how you return your observable

Lets break the code down

let studentsInfo = this.http.get<any>(requestUrl).pipe(map(o => o.students));

In the above studentsInfo will be of type Observable<any>

Next line is as per below

return studentsInfo.pipe(
  map(students => {
    students.first_name, students.last_name
  }
));

Lets have a look at the below section

{
  students.first_name, students.last_name
}

This part of the section actually has no return statement hence by default javascript returns undefined!

Solution

To use arrow function without a return statement, you will need to wrap {} inside a () like below

students => ({ })

Below will work

getStudentsName(): Observable<any> {
  return this.http.get<any[]>(`${this.routeURL}/students`).pipe(
    map(o => o.students));
  }
0
MoxxiManagarm On

Your problem is, that students is an array, but you handle it as an object. You need to add a nested map: 1 for rxjs, 1 for the array

return studentsInfo.pipe(
  map(studentsArray => studentsArray.map(student => ({
    first_name: student.first_name,
    last_name: student.last_name
  }))),
);

PS.: Using types instead of any would have shown you that. Neither you nor the other responders saw this issue due to missing typing.