Используя 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. добавьте свойство, которое объединяет значения, по которым вы хотите фильтровать
Если этого недостаточно, вам следует подумать об изменении / расширении ваших данных, чтобы разрешить ваш вариант использования. Например: вы можете заполнить жанр + привести в одно свойство, которое вы просто используете для этого фильтра.
"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);
});
Дэвид Ист написал библиотеку 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 использует для строковых значений, будет таким же, как и хронологический порядок.
Такое объединение значений в свойстве может работать с более чем двумя значениями, но вы можете выполнить фильтрацию диапазона только по последнему значению в составном свойстве.
Особый вариант этого реализован библиотекой GeoFire для Firebase . Эта библиотека объединяет широту и долготу местоположения в так называемый геохэш , который затем можно использовать для выполнения запросов диапазона в реальном времени в 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
orderBy()
вызовов вызовут ошибку, потому что клиенты в настоящее время дают неожиданные результаты. Возможно, это совпадение сработало в вашем тесте, но не предназначено для общей работы (хотя мы бы хотели добавить его!).