如何在JSON数据中找到所有满足特定条件的项目?

时间:2019-10-29 07:39:39

标签: javascript arrays json angular loops

我从API调用获取数据。我有很多对很多的关系-我会和人们一起看电影。一部电影被很多人看,一个人可以看许多电影。 因此,在Angular Frontend中,单击某个人时,应该可以更详细地查看该人的视图,包括其观看的电影列表。

当我运行此代码(person-detail.component.ts)时:

  public selectedperson: any = []
/*Array that contains data from the selected person*/
  public movie: any = []
/*Array that contains all the movie-person connections (movie-name and person_id)*/
  public selectedmovie: any = []
/*array that should contain all the movies the selectedperson has watched*/
/*some code*/
getMovies(){
    const url ='http://localhost:4000/api/people-movies';
    this.http.get(url).subscribe(movie => {
      this.movie = movie;
      this.selectedmovie=this.movie.find(item=>
        {
          for (var i = 0; i < this.movie.arrayLength; i++) {
            if(item['person_id']===this.selectedperson.person_id)
            {
              return true;
            }
          return false;
        }
        });
      console.log(this.selectedmovie, this.selectedperson.person_id);
      return this.selectedmovie;
    });
  }

它不起作用-但没有此循环(并且如果我离开If语句):

 for (var i = 0; i < this.movie.arrayLength; i++) {
}

它只会返回此人的一部电影-因此,一旦找到电影,它就会停止播放。但是由于我要列出所有电影,因此需要循环播放。

那么循环出现了什么问题?

编辑: 选定人员中的样本数据(已填写): 被选人:

[{"person_id"=34, "name"="john"}]

电影(通过具有上述URL的API调用获取此数据):

[{"person_id"=33, "movie"="Titanic"}{"person_id"=33, "movie"="Star Wars"}{"person_id"=34, "movie"="Titanic"}{"person_id"=34, "movie"="Star Wars"}{"person_id"=34, "movie"="Indiana Jones"}{"person_id"=35, "movie"="Titanic"}]

想要最终结果(对于ID为34的人)

Titanic
Star Wars
Indiana Jones

5 个答案:

答案 0 :(得分:1)

您可以尝试这样。

this.selectedmovie = this.selectedmovie.filter(item => {
  for (var i = 0; i < this.movie.arrayLength; i++) {
     if (item['person_id'] === this.selectedperson.person_id) {
        return true;
     }
   }
   return false;
});

注意:Javascript array.find方法返回提供的数组中满足提供的测试功能的第一个元素的值。

答案 1 :(得分:1)

您的代码有些错误,但是我将从我认为适合您的解决方案开始:

getMovies(){
    const url ='http://localhost:4000/api/people-movies';
    this.http.get(url).subscribe(movie => {
      this.movie = movie;
      this.selectedmovie=this.movie.filter(item=> item['person_id'] === this.selectedperson.person_id );
      console.log(this.selectedmovie, this.selectedperson.person_id);
      return this.selectedmovie.map(movie.movie);
    });
  }

现在,您的代码有什么问题:

  1. 您尝试通过激活自身上的selectedmovie来填充空数组find,但它是空的...而是使用{{1}中的电影填充它}数组。

  2. 您正在使用movie,对文档(here)的简单了解可以清楚地表明,它仅返回满足测试功能的第一个元素。取而代之的是使用find,它有点相同,但会遍历整个数组并返回所有满足测试的对象。

  3. 您可以在不使用filter的情况下进行for循环-这实际上是不需要循环的明显信号。

  4. 当整个检查是单个布尔表达式时,无需返回“ true”或“ false”,它将内联返回。

  5. 单方面来说,您的变量名称确实很难理解。例如,包含电影的数组最好称为“电影”,而当您使用数组函数对其进行迭代时,每个元素都可以称为“电影”。两者使用相同的名称确实令人困惑。还要尝试使用驼峰表示法(selectedMovie),这样会使名称更清晰。

**注意:我的解决方案只会按照您想要的方式从“ getMovies”返回数组,因为i链接在返回值上。如果您希望仅使用电影名称作为字符串而不是整个movie-perosn_id对象来填充.map,只需将selectedmovie链接到.map,就像这样:

filter

希望对您有所帮助:)

答案 2 :(得分:1)

您可以这样获得所需的结果:

const movie = [
   {"person_id":33, "movie":"Titanic"},
   {"person_id":33, "movie":"Star Wars"},
   {"person_id":34, "movie":"Titanic"},
   {"person_id":34, "movie":"Star Wars"},
   {"person_id":34, "movie":"Indiana Jones"},
   {"person_id":35, "movie":"Titanic"}
];

let selectedperson = [{"person_id":34, "name":"john"}];

let moviesByPerson = movie.filter(f=>
    selectedperson.some(s=> f['person_id'] == s['person_id']));

console.log(`moviesByPerson: `, moviesByPerson);

在您的代码中:

getMovies(){
    const url ='http://localhost:4000/api/people-movies';
    this.http.get(url).subscribe(movie => {
      this.movie = movie;
      this.selectedmovie = movie.filter(f=>
           selectedperson.some(s=> f['person_id'] == s['person_id']));

      console.log(this.selectedmovie, this.selectedperson.person_id);

      return this.selectedmovie;
    });
  }

此外,请尝试将HTTP调用移入服务,因为这是区分关注点的好习惯。 As Angular docs says:

  

组件不应该直接获取或保存数据,它们当然   不应故意提供虚假数据。他们应该专注于呈现   数据并委托对服务的数据访问。

答案 3 :(得分:1)

某些问题,如前所述,您正在使用find,它将仅返回第一个匹配项(如果存在)。您正在寻找filter来过滤与ID匹配的电影。另外,您正在尝试从subscribe返回,这是行不通的。我也会改变你的做法。 请勿使用any,它违反了 Type 脚本的目的。因此,键入数据(例如使用接口)将为您提供帮助,因为编译器会告诉您是否执行了与模型不符的操作,这使调试变得更加容易!

我还将所有http请求移至服务,该组件仅订阅该http请求的结果。所以总的来说,我建议以下几点:

interface Movie {
  person_id: number;
  movie: string;
}

interface Person {
  person_id: number;
  name: string;
}

服务:

import { map } from "rxjs/operators";

// ...

getFilteredMovies(id: number) {
  const url ='http://localhost:4000/api/people-movies';
  return this.http.get<Movie[]>(url).pipe(
    map((movies: Movie[]) => {
      return movies.filter((m: Movie) => m.person_id === id)
    })
  )
}

组件:

movies = <Movie[]>[];

selectedPerson = <Person>{ person_id: 34, name: "john" };

constructor(private myService: MyService) {}

ngOnInit() {
  this.myService
    .getFilteredMovies(this.selectedPerson.person_id)
    .subscribe((data: Movie[]) => {
      this.movies = data;
    });
}

因此,我们已经在服务中处理了过滤,并且组件仅订阅。 如果,您在其他不希望执行过滤的地方调用了此函数,然后在组件中执行过滤。

STACKBLITZ demo 和上面的代码。

答案 4 :(得分:0)

我终于解决了它-感谢erveryone的帮助,尤其是@Gibor! 这是遇到类似问题的人的代码: 但是,请注意,该代码绝非完美,必须以多种方式加以改进(例如,使用循环查找所有电影)。我只是将其发布在这里,希望对遇到类似问题的人有所帮助... component.ts:

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ActivatedRoute} from '@angular/router';

@Component({
  selector: 'app-people-detail',
  templateUrl: './people-detail.component.html',
  styleUrls: ['./people-detail.component.css']
})
export class PeopleDetailComponent implements OnInit {
  public data: any = []
  public selectedperson: any = []
  public movies: any = []
  public moviesByPerson: any = []

  constructor(
    public http: HttpClient, 
    public route: ActivatedRoute) { }

getPeople()
{
  const person_id = this.route.snapshot.paramMap.get('person_id')
  const people_url ='http://localhost:4000/api/people'
  const movies_url ='http://localhost:4000/api/person-movie'
  this.http.get(people_url).subscribe
    (data => 
      {
        this.data = data;
        this.selectedperson=this.data.find
        (item=>
          {
            if(item['person_id']===person_id)
            {
             return true;
            }
            return false;
          }
        )
        this.http.get(movies_url).subscribe
    (movies => 
      {
        this.movies = movies;
        this.moviesByPerson=this.movies.filter(item => item.person_pk === this.selectedperson.person_pk)
      }
    )
    console.log(this.selectedperson, this.moviesByPerson)
        return this.selectedperson, this.moviesByPerson
      }
    )
}
  ngOnInit()
  {
    this.getPeople()
  }
}

component.html:

<div><span>ID: </span>{{selectedperson.person_id}}</div>
<h1>{{selectedperson.name}}</h1>
<p>{{selectedperson.age}}</p>
<p></p>
<table>
    <thead>
        <tr>
            <th>Movies</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>{{moviesByPerson[0].movie}}</td>
        </tr>
        <tr>
            <td>{{moviesByPerson[1].movie}}</td>
        </tr>
        <tr>
            <td>{{moviesByPerson[2].movie}}</td>
        </tr>
    </tbody>
</table>