# #javascript #firebase #google-cloud-firestore
Вопрос:
Я обновляю проект с Firebase версии 8 до версии 9. У меня есть условно отфильтрованные запросы, которые раньше были структурированы следующим образом:
let query = db.collection("collectionName").orderBy("timestamp")
if (filters.selectedStaff) {
query = query.where("id", "==", filters.selectedStaff.id);
}
if (filters.selectedStudent) {
query = query.where("studentIDs", "array-contains", filters.selectedStudent.id);
}
Затем запрос выполняется в крючке, который пересылается каждый раз, когда меняются фильтры. Используя версию 8, это работает идеально.
В версии 9 запросы теперь строятся в соответствии с форматом, в котором каждый запрос передается в качестве параметра функции запроса. Обычный запрос будет выглядеть так:
query(collection(db, "collectionName"), where("id", "==", filters.selectedStaff.id), where("studentIDs", "array-contains", filters.selectedStudent.id), orderBy("timestamp"))
Вы все еще можете сохранить функцию where в качестве переменной и передать эту переменную в качестве параметра функции запроса:
let w1 = where("id", "==", filters.selectedStaff.id)
let w2 = where("studentIDs", "array-contains", filters.selectedStudent.id)
query(collection(db, "collectionName"), w1, w2, orderBy(timestamp))
Но проблема, которую я не понял, как решить, заключается в том, как сделать условия where условными. Не похоже, что firebase допускает, чтобы значение предложения where было любым. Например, если значение w1 по умолчанию равно:
let w1 = where("id", "==", "*")
Если вы попытаетесь сделать оператор также переменной и по умолчанию использовать что-либо, кроме==, например != :
let w1 = where("id", "!=", "")
Firebase заставляет вас установить первичную сортировку по полю в предложении where, которое не будет работать, если вы пытаетесь выполнить сортировку по другому полю, как я (метка времени).
В конечном счете, обходной путь, который работает, состоит в том, чтобы создать поле в каждом документе, имеющее одинаковое значение, например логическое значение true, а затем установить, чтобы все ваши предложения where изначально были равны этому значению, а затем динамически изменялись:
let w1 = where("randomField", "==", true)
let w2 = where("randomField", "==", true)
if(filters.selectedStaff){
w1 = where("id", "==", filters.selectedStaff.id)
}
if(filters.selectedStudent){
w2 = where("studentIDs", "array-contains", filters.selectedStudent.id)
}
query(collection(db, "collectionName"), w1, w2, orderBy(timestamp))
Хотя это работает, мне кажется, что это действительно ненужный обходной путь, и я хотел посмотреть, знает ли кто-нибудь лучший способ добиться того же результата.
Ответ №1:
Вы можете продолжать использовать существующую логику, изменился только синтаксис. Попробуйте выполнить рефакторинг кода, как показано ниже:
let q = query(collection("db", "collectionName"), orderBy("timestamp"));
if (filters.selectedStaff) {
q = query(q, where("id", "==", filters.selectedStaff.id));
}
if (filters.selectedStudent) {
q = query(q, where("studentIDs", "array-contains", filters.selectedStudent.id));
}
const snapshot = await getDocs(q);
Другой подход состоял бы в том, чтобы условно поместить эти условия в массив:
const conditions = [orderBy("timestamp")]
if (filters.selectedStaff) {
conditions.push(where("id", "==", filters.selectedStaff.id));
}
if (filters.selectedStudent) {
conditions.push(where("studentIDs", "array-contains", filters.selectedStudent.id));
}
const q = query(collection(db, "collectionName"), ...conditions);
// Do note the spread operator ^
const snapshot = await getDocs(q);
Комментарии:
1. Оба работают замечательно, большое вам спасибо за помощь. Условное включение предложений в запрос также является действительно элегантным и универсальным решением.