Запрос, основанный на нескольких предложениях в Firebase
{
"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'
И lead = 'Jack Nicholson'
?
Какие у меня есть варианты?
Ответы
Ответ 1
Используя Новый API запросов Firebase, у вас может возникнуть соблазн попробовать следующее:
// !!! 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());
});
Но как @RobDiMarco из Firebase говорит в комментариях:
несколько вызовов 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 написал библиотеку
И затем запросите комедии 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 делает на строковых значениях, будет таким же, как и хронологическое упорядочение.
Это объединение значений в свойстве может работать с более чем двумя значениями, но вы можете использовать фильтр диапазона только для последнего значения в составном свойстве.
Очень специальный вариант этого реализуется библиотекой GeoFire для Firebase , который затем может использоваться для выполнения запросов в реальном времени на Firebase.
Еще одна альтернатива - сделать то, что мы все сделали до того, как был добавлен новый API запросов: создайте индекс в другом node:
"movies"
// the same structure you have today
"by_genre"
"comedy"
"by_lead"
"Jack Nicholson"
"movie1"
"Jim Carrey"
"movie3"
"Horror"
"by_lead"
"Jack Nicholson"
"movie2"
Есть, вероятно, больше подходов. Например, этот ответ выделяет альтернативный древовидный пользовательский индекс:
Ответ 2
Я написал персональную библиотеку, которая позволяет вам заказывать несколько значений, причем все заказы выполняются на сервере.
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) {
}
});