Несколько условий предложения where на ссылке базы данных Firebase в Android. Как выполнить это действие [duplicate]

Я согласен с ответом от zacherates.

Но вы можете сделать вызов intern () в ваших нелиберальных строках.

Из примера zacherates:

// ... but they are not the same object
new String("test") == "test" ==> false 

Если вы ставите нелитеральное равенство строки, это правда

new String("test").intern() == "test" ==> true 
180
задан dda 5 December 2017 в 05:59
поделиться

4 ответа

Используя новый 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 говорит в комментариях:

< blockquote>

Несколько вызовов 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 делает на строковых значениях, будет таким же, как и хронологическое упорядочение.

Это объединение значений в свойстве может работать с более чем двумя значениями, но вы можете использовать фильтр диапазона только для последнего значения в составном свойстве.

Очень специальный вариант Это реализовано библиотекой GeoFire для Firebase . Эта библиотека объединяет широту и долготу местоположения в так называемый 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

169
ответ дан Frank van Puffelen 15 August 2018 в 20:10
поделиться
  • 1
    Когда это будет официально выпущено на следующей неделе, несколько вызовов orderBy() вызовут ошибку, так как клиенты в настоящее время дают неожиданные результаты. Вполне возможно, что он по совпадению работал в вашем тесте, но не построен для работы в целом (хотя мы хотели бы добавить его!). – Rob DiMarco 3 November 2014 в 00:37
  • 2
    Это все еще актуально в 2016 году с Firebase V3? Разве нет лучших способов сделать это? – Pier 3 June 2016 в 18:21
  • 3
    Это по-прежнему актуально. – Frank van Puffelen 3 June 2016 в 18:33
  • 4
    Почему мы не можем использовать .equalTo('comedy') вместо .startAt('comedy').endAt('comedy')? – JCarlos 1 November 2016 в 15:33
  • 5
    Это 2018 год, нет ли простого решения для этого? Это похоже на запрос 101 в реляционной базе данных. И учитывая все комментарии к видео Дэвида о SQL # 8, я бы ожидал, что Google исправит его к настоящему времени. Я пропустил некоторое обновление? – Snake 24 February 2018 в 22:47

Я написал персональную библиотеку, которая позволяет вам заказывать несколько значений со всеми заказами, выполненными на сервере.

Встретить Querybase!

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));
29
ответ дан David East 15 August 2018 в 20:10
поделиться
  • 1
    Любые определения типа TypeScript для вашей библиотеки? – Levi Fuller 19 June 2016 в 20:29
  • 2
    Это написано в TS! Так что просто импорт :) – David East 19 June 2016 в 20:30
  • 3
    вы знаете, почему они сделали базу данных настолько ограничительной? – Ced 21 August 2017 в 21:38
  • 4
    Любой вариант для версии IOS Swift / Android – mding5692 12 September 2017 в 19:46
  • 5
    Дэвид, любая эквивалентность Android и Java? – Snake 24 February 2018 в 22:48
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) {

    }
});
2
ответ дан Mehmed 15 August 2018 в 20:10
поделиться
  • 1
    Нет метода getLead () объекта DataSnapshot. – Parag Kadam 31 July 2016 в 13:59
  • 2
    Он преобразовал его в объект Movie и предположил, что есть метод getLead (). – Kim G Pham 14 December 2017 в 23:20
  • 3
    Большое спасибо. Он работает, например, больше, где статьи – Nuwan Withanage 18 July 2018 в 06:16
0
ответ дан jaleel 29 October 2018 в 03:23
поделиться
Другие вопросы по тегам:

Похожие вопросы: