如何在JSON数据中找到符合特定条件的所有项



我从API-Call获取数据。我有一种多对多的关系——我会在电影中向人们解释这一点。一部电影被很多人看,一个人可以看很多电影。因此,在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++) {
}

它只返回这个人的一部电影,所以它一找到电影就停止。但既然我想列出所有的电影,我需要循环。

那么我在循环中做错了什么呢?

编辑:selectedperson中的示例数据(已填充):选定人员:

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

电影(从API调用中获取上述URL的数据):

[{"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

您的代码有一些问题,但我将从我认为适合您的解决方案开始:

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. 您试图通过在自身上激活find来填充空数组selectedmovie,但它是空的。。。相反,用movie数组中的电影填充它。

  2. 您使用的是find,简单地看一下文档(这里)就会发现它只返回满足测试函数的第一个元素。相反,使用了filter,它有点相同,但会遍历整个数组并返回所有满足测试的对象。

  3. 你在不使用i的情况下创建了一个for循环——这是一个很强的迹象,表明你实际上并不需要那个循环。

  4. 当整个检查是一个布尔表达式时,不需要返回"true"或"false",而是内联返回。

  5. 只是一方面不是,你的各种各样的名字真的很难跟上。例如,包含movies的数组最好称为"movies",当您使用数组函数对其进行迭代时,每个元素都可以称为"movie"。两者使用相同的名称实在令人困惑。同时尝试使用驼色大小写表示法(selectedMovie),可以使名称更清晰。

**注意:我的解决方案只会按照您想要的方式从"getMovies"返回数组,因为.map被链接在返回值上。如果您希望selectedmovie只填充电影名称作为字符串,而不是整个movie-prosn_id对象,只需将.map链接到filter,如下所示:

this.selectedmovie=this.movie.filter(item=> item['person_id'] === this.selectedperson.person_id ).map(movie => movie.movie);

希望有帮助:)

您可以获得如下所需的结果:

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调用转移到服务中,因为分离关注点是一种很好的做法。正如Angular文档所说:

组件不应该直接获取或保存数据,当然不应该故意提供虚假数据。他们应该专注于展示数据和将数据访问委托给服务。

您可以这样尝试。

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.fund方法返回所提供数组中满足所提供测试函数的第一个元素的值。

有些问题,如前所述,您正在使用find,它将只返回第一个匹配(如果存在)。您正在查找filter以筛选与id匹配的电影。此外,您正在尝试从subscribe返回,但这不起作用。我也会稍微改变一下你的做法不要使用any,它违背了类型脚本的目的。因此,键入您的数据,例如使用接口,这将对您有所帮助,因为编译器可以告诉您所做的事情是否与您的模型不符,这将使调试更加容易!

此外,我会将所有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;
});
}

因此,我们已经在服务中处理过滤,并且组件只订阅IF如果您在其他地方调用此函数,而不希望执行筛选,则改为在组件中执行筛选。

使用上面的代码堆叠BLITZ演示

我终于解决了它-感谢Serveryone的帮助,尤其是@Gibor!以下是针对面临类似问题的人的代码:然而,要知道,这个代码绝非完美,必须在许多方面进行改进(例如,使用循环查找所有电影)。我只是把它贴在这里,希望它能帮助有类似问题的人。。。组件.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>

最新更新