질문
{
"movies": {
"movie1": {
"genre": "comedy",
"name": "As good as it gets",
"lead": "Jack Nicholson"
},
"movie2": {
"genre": "Horror",
"name": "The Shining",
"lead": "Jack Nicholson"
},
"movie3": {
"genre": "comedy",
"name": "The Mask",
"lead": "Jim Carrey"
}
}
}
저는 Firebase 초보자입니다. 여기서 genre = 'comedy'
AND lead = 'Jack Nicholson'
위의 데이터에서 결과를 검색하려면 어떻게해야하나요?
어떤 옵션이 있습니까?
답변1
Firebase의 쿼리 API 를 사용하면 다음과 같이 시도해 볼 수 있습니다.
// !!! THIS WILL NOT WORK !!!
ref
.orderBy('genre')
.startAt('comedy').endAt('comedy')
.orderBy('lead') // !!! THIS LINE WILL RAISE AN ERROR !!!
.startAt('Jack Nicholson').endAt('Jack Nicholson')
.on('value', function(snapshot) {
console.log(snapshot.val());
});
그러나 Firebase의 @RobDiMarco는 댓글에서 다음과 같이 말합니다.
여러 orderBy()
호출은 오류를 발생시킵니다.
따라서 위의 코드가 작동하지 않습니다 .
나는 효과가있을 세 가지 접근 방식을 알고 있습니다.
1. 서버에서 대부분을 필터링하고 나머지를 클라이언트에서 수행
할 수 있는 작업은 서버에서 orderBy (). startAt () ./ endAt ()
하나를 실행하고 나머지 데이터를 풀다운 한 다음 JavaScript 코드에서 필터링하는 것입니다. 고객.
ref
.orderBy('genre')
.equalTo('comedy')
.on('child_added', function(snapshot) {
var movie = snapshot.val();
if (movie.lead == 'Jack Nicholson') {
console.log(movie);
}
});
2. 필터링할 값을 결합하는 속성 추가
충분하지 않은 경우 사용 사례를 허용하도록 데이터를 수정 / 확장하는 것을 고려해야합니다. 예를 들어 genre + lead가 필터에 사용하는 단일 속성에 넣을 수 있습니다.
"movie1": {
"genre": "comedy",
"name": "As good as it gets",
"lead": "Jack Nicholson",
"genre_lead": "comedy_Jack Nicholson"
},...
기본적으로 이러한 방식으로 고유 한 다중 열 인덱스를 작성하고 다음을 사용하여 쿼리 할 수 있습니다.
ref
.orderBy('genre_lead')
.equalTo('comedy_Jack Nicholson')
.on('child_added', function(snapshot) {
var movie = snapshot.val();
console.log(movie);
});
David East는 이러한 속성을 생성하는 데 도움이되는 QueryBase 라이브러리 를 작성했습니다.
상대 / 범위 쿼리를 수행 할 수도 있습니다. 카테고리 및 연도별로 영화를 쿼리 할 수 있다고 가정 해 보겠습니다. 다음 데이터 구조를 사용합니다.
"movie1": {
"genre": "comedy",
"name": "As good as it gets",
"lead": "Jack Nicholson",
"genre_year": "comedy_1997"
},...
그리고 다음과 같이 90 년대 코미디를 검색합니다.
ref
.orderBy('genre_year')
.startAt('comedy_1990')
.endAt('comedy_2000')
.on('child_added', function(snapshot) {
var movie = snapshot.val();
console.log(movie);
});
연도 이상을 필터링해야하는 경우 다른 날짜 부분을 내림차순으로 추가해야합니다 (예 : "comedy_1997-12-25"
. 이렇게하면 Firebase가 문자열 값에 대해 수행하는 사전 식 순서가 시간 순서와 동일합니다.
속성의 값 조합은 세 개 이상의 값에 대해 작동 할 수 있지만 복합 속성의 마지막 값에 대해서만 범위 필터를 수행 할 수 있습니다.
이것의 매우 특별한 변형은 Firebase 용 GeoFire 라이브러리 에 의해 구현됩니다. 이 라이브러리는 위치의 위도와 경도를 소위 Geohash 로 결합합니다. Firebase에서 실시간 범위 쿼리를 수행하는 데 사용됩니다.
3. 프로그래밍 방식으로 사용자 지정 인덱스 만들기
또 다른 대안은 이 새로운 쿼리 API가 추가되기 전에 우리가 모두 수행 한 작업을 수행하는 것입니다. 다른 노드에 인덱스를 만듭니다.
"movies"
// the same structure you have today
"by_genre"
"comedy"
"by_lead"
"Jack Nicholson"
"movie1"
"Jim Carrey"
"movie3"
"Horror"
"by_lead"
"Jack Nicholson"
"movie2"
아마도 더 많은 접근 방식이있을 것입니다. 예를 들어 이 답변은 대체 트리 모양의 커스텀 색인을 강조합니다. https://stackoverflow.com/a/34105063
이러한 옵션 중 어느 것도 작동하지 않지만 Firebase에 데이터를 저장하려는 경우 Cloud Firestore 데이터베이스 .
Cloud Firestore는 단일 쿼리에서 여러 동등 필터를 처리 할 수 있지만 범위 필터는 하나만 있습니다. 내부적으로는 기본적으로 동일한 쿼리 모델을 사용하지만 복합 속성을 자동으로 생성하는 것과 같습니다. 복합 쿼리 에 대한 Firestore Document를 참조하세요.
답변2
저는 서버에서 모든 순서를 지정하여 여러 값으로 주문할 수있는 private 라이브러리를 작성했습니다.
Querybase는 Firebase 데이터베이스 참조와 색인을 생성하려는 필드 배열을 가져옵니다. 새 레코드를 만들면 여러 쿼리를 허용하는 키 생성을 자동으로 처리합니다. 주의 할 점은 직선 등가 만 지원한다는 것입니다 (보다 작거나 크지 않음).
const databaseRef = firebase.database().ref().child('people');
const querybaseRef = querybase.ref(databaseRef, ['name', 'age', 'location']);
// Automatically handles composite keys
querybaseRef.push({
name: 'David',
age: 27,
location: 'SF'
});
// Find records by multiple fields
// returns a Firebase Database ref
const queriedDbRef = querybaseRef
.where({
name: 'David',
age: 27
});
// Listen for realtime updates
queriedDbRef.on('value', snap => console.log(snap));
답변3
var ref = new Firebase('https://your.firebaseio.com/');
Query query = ref.orderByChild('genre').equalTo('comedy');
query.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot movieSnapshot : dataSnapshot.getChildren()) {
Movie movie = dataSnapshot.getValue(Movie.class);
if (movie.getLead().equals('Jack Nicholson')) {
console.log(movieSnapshot.getKey());
}
}
}
@Override
public void onCancelled(FirebaseError firebaseError) {
}
});
답변4
Frank의 대답은 좋지만 Firestore는 array-contains
최근에는 AND 쿼리를 더 쉽게 수행 할 수 있습니다.
filters
필드를 만들어 필터를 추가 할 수 있습니다. 필요한만큼 값을 추가 할 수 있습니다. 예를 들어 코미디 및 Jack Nicholson으로 필터링하려면 comedy_Jack Nicholson
값을 추가 할 수 있지만 원하는 경우 코미디 < / em> 및 2014 필드를 더 만들지 않고도 comedy_2014
값을 추가 할 수 있습니다.
{
"movies": {
"movie1": {
"genre": "comedy",
"name": "As good as it gets",
"lead": "Jack Nicholson",
"year": 2014,
"filters": [
"comedy_Jack Nicholson",
"comedy_2014"
]
}
}
}
답변5
Firebase는 여러 조건을 사용한 쿼리를 허용하지 않습니다.그러나 나는 이것에 대한 방법을 찾았습니다.
데이터베이스에서 필터링 된 초기 데이터를 다운로드하여 배열 목록에 저장해야합니다.
Query query = databaseReference.orderByChild("genre").equalTo("comedy");
databaseReference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
ArrayList<Movie> movies = new ArrayList<>();
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
String lead = dataSnapshot1.child("lead").getValue(String.class);
String genre = dataSnapshot1.child("genre").getValue(String.class);
movie = new Movie(lead, genre);
movies.add(movie);
}
filterResults(movies, "Jack Nicholson");
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
데이터베이스에서 필터링 된 초기 데이터를 얻은 후에는 백엔드에서 추가 필터링을 수행해야합니다.
public void filterResults(final List<Movie> list, final String genre) {
List<Movie> movies = new ArrayList<>();
movies = list.stream().filter(o -> o.getLead().equals(genre)).collect(Collectors.toList());
System.out.println(movies);
employees.forEach(movie -> System.out.println(movie.getFirstName()));
}
답변6
ref.orderByChild("lead").startAt("Jack Nicholson").endAt("Jack Nicholson").listner....
작동합니다.
출처 : https://stackoverflow.com/questions/26700924/query-based-on-multiple-where-clauses-in-firebase