Используя 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()
вызовов вызовут ошибку, потому что клиенты в настоящее время дают неожиданные результаты. Возможно, это совпадение сработало в вашем тесте, но не предназначено для общей работы (хотя мы бы хотели добавить его!)..equalTo('comedy')
вместо.startAt('comedy').endAt('comedy')
?Я написал личную библиотеку, которая позволяет упорядочивать по нескольким значениям, причем все упорядочения выполняются на сервере.
Встречайте Querybase!
Querybase берет ссылку на базу данных Firebase и массив полей, по которым вы хотите индексировать. Когда вы создаете новые записи, он автоматически обрабатывает генерацию ключей, которые допускают множественные запросы. Предостережение заключается в том, что он поддерживает только прямую эквивалентность (не меньше или больше, чем).
источник
источник
Фрэнк ответил хорошо, но Firestore представил
array-contains
недавно который облегчает выполнение запросов AND.Вы можете создать
filters
поле для добавления ваших фильтров. Вы можете добавить столько значений, сколько вам нужно. Например, чтобы отфильтровать по комедии и Джеку Николсону, вы можете добавить значение,comedy_Jack Nicholson
но если вы хотите, чтобы по комедии и 2014 вы могли добавить значениеcomedy_2014
без создания дополнительных полей.источник
Firebase не позволяет запрашивать несколько условий. Тем не менее, я нашел способ обойти это:
Нам нужно загрузить исходные отфильтрованные данные из базы данных и сохранить их в списке массивов.
Как только мы получим исходные отфильтрованные данные из базы данных, нам нужно выполнить дополнительную фильтрацию в нашем бэкэнде.
источник
Это будет работать
источник