Строки в Java неизменяемы. Это означает, что всякий раз, когда вы пытаетесь изменить / изменить строку, вы получаете новый экземпляр. Вы не можете изменить исходную строку. Это сделано для того, чтобы эти экземпляры строк могли кэшироваться. Типичная программа содержит множество ссылок на строки и кеширование этих экземпляров, что может уменьшить объем памяти и увеличить производительность программы.
При использовании оператора == для сравнения строк вы не сравниваете содержимое строки , но фактически сравнивают адрес памяти. Если они равны, в противном случае они вернут true и false. Если значение равно в строке, сравнивает содержимое строки.
Итак, вопрос в том, что все строки кэшируются в системе, как получается ==
возвращает false, тогда как equals возвращает true? Ну, это возможно. Если вы создадите новую строку, например String str = new String("Testing")
, вы создадите новую строку в кеше, даже если в кеше уже содержится строка с тем же содержимым. Короче говоря, "MyString" == new String("MyString")
всегда будет возвращать false.
Java также говорит о функции intern (), которая может использоваться в строке, чтобы сделать ее частью кеша, поэтому "MyString" == new String("MyString").intern()
вернет true.
Примечание: == оператор намного быстрее, чем равен только потому, что вы сравниваете два адреса памяти, но вы должны быть уверены, что код не создает новые экземпляры String в коде. В противном случае вы столкнетесь с ошибками.
Используя новый 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()
вызовут ошибку
. Поэтому мой код выше не будет работать.
Я знаю о трех подходах, которые будут работать.
Что вы можете выполнить , выполните один 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);
}
});
. Если это недостаточно, вам следует рассмотреть возможность изменения / расширения ваших данных, чтобы разрешить использование вашего прецедента. Например: вы можете набить 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.
. Еще одна альтернатива - сделать то, что мы все сделали до того, как был добавлен новый 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
Я написал персональную библиотеку, которая позволяет вам заказывать несколько значений со всеми заказами, выполненными на сервере.
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));
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) {
}
});
orderBy()
вызовут ошибку, так как клиенты в настоящее время дают неожиданные результаты. Вполне возможно, что он по совпадению работал в вашем тесте, но не построен для работы в целом (хотя мы хотели бы добавить его!). – Rob DiMarco 3 November 2014 в 00:37.equalTo('comedy')
вместо.startAt('comedy').endAt('comedy')
? – JCarlos 1 November 2016 в 15:33