Как использовать VueUse useFirestore() с Where QueryConstraint?

У меня есть документ Firestore users, который выглядит примерно так:

{
    currentCompanyId: "123",
    displayName: "Mary Jane" 
}

И документ Firestore websites, который выглядит примерно так:

{
    companyId: "123",
    homePageUrl: "https://www.google.com/"
}

Теперь я пытаюсь использовать оболочку VueUse useFirestore() для отображения websites документа.

Для этого я ссылаюсь на свойство currentCompanyId документа users внутри ограничения запроса where следующим образом:

<template>
  <div>
    {{ websites?.[0] }}
  </div>
</template>

<script setup lang = "ts">
import { useAuth } from '@vueuse/firebase/useAuth';
import { useFirestore } from '@vueuse/firebase/useFirestore';
import { collection, doc, query, where } from 'firebase/firestore';
import { auth, db } from 'src/config/firebase';
import { User } from 'src/types';
import { computed } from 'vue';

const { user: authUser } = useAuth(auth);
const userDocRef = doc(db, `users/${authUser.value?.uid}`);
const user = useFirestore<User>(userDocRef);

const websiteQuery = computed(() =>
  query(
    collection(db, 'websites'),
    where('companyId', '==', user.value?.currentCompanyId) // This produces an error
    // where('companyId', '==', '123') // This works, but is not practical
  )
);
const websites = useFirestore(websiteQuery);
</script>

Жесткое кодирование companyId значения 123 работает.

Но всякий раз, когда я использую user.value?.currentCompanyId внутри вычисляемой ссылки, возникает ошибка, говорящая следующее:

TypeError: правая часть "in" должна быть объектом, полученным нулем

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
70
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Попробуйте передать QueryConstraint только тогда, когда значение определено следующим образом:

const websiteQuery = computed(() => {
  const queryContraints: any = [];
  const currentCompanyId = user.value?.currentCompanyId;

  if (currentCompanyId) queryContraints.push(where("companyId", "= = ", currentCompanyId));
  return query(
    collection(db, 'websites'),
    ...queryContraints
  )
});

Однако это вернет все документы, если вы не укажете ограничение where(), поэтому, возможно, попробуйте запустить запрос только тогда, когда он определен, то есть после загрузки состояния аутентификации. onAuthStateChanged() здесь может пригодиться.

Спасибо, это работает, и я уже гарантирую, что состояние аутентификации загружается при запуске приложения, так что это не проблема. Я также заметил, что я могу использовать шаблонные литералы (обратные галочки) для такого значения `${user.value?.currentCompanyId}`, и это работает. Можете ли вы пролить свет на то, почему это работает? Я думал, что литерал пустого шаблона будет undefined и, следовательно, также выдаст ошибку, но этого не происходит.

TinyTiger 15.09.2022 00:30

@TinyTiger, когда вы используете литералы шаблонов, результатом будет "undefined" (в виде строки), так что это допустимое значение. Он будет искать документы, где companyId равно "undefined" (строка). Но undefined не является допустимым значением.

Dharmaraj 15.09.2022 05:41
Ответ принят как подходящий

Я понял.

Проблема была в том, что user.value?.currentCompanyId изначально null.

Вот снова сообщение об ошибке:

TypeError: правая часть "in" должна быть объектом, полученным нулем

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

Обертывание запроса в ссылку computed в конечном итоге изменит значение с null на что-то другое при его обновлении. Но изначально это null. И в этом причина ошибки.

Чтобы решить эту проблему, вы можете установить некоторые начальные свойства user в useFirestore. Таким образом, ограничение запроса Where изначально будет использовать это ненулевое значение. Даже пустая строка будет в порядке. Вы можете использовать все, что не является null.

Вот полный код:

<template>
  <div>
    {{ websites?.[0] }}
  </div>
</template>

<script setup lang = "ts">
import { useAuth } from '@vueuse/firebase/useAuth';
import { useFirestore } from '@vueuse/firebase/useFirestore';
import { collection, doc, query, where } from 'firebase/firestore';
import { auth, db } from 'src/config/firebase';
import { User } from 'src/types';
import { computed } from 'vue';

const { user: authUser } = useAuth(auth);
const userDocRef = doc(db, `users/${authUser.value?.uid}`);
const user = useFirestore<User>(userDocRef, { currentCompanyId: '' }); // <-- See change here

const websiteQuery = computed(() =>
  query(
    collection(db, 'websites'),
    where('companyId', '==', user.value?.currentCompanyId)
  )
);
const websites = useFirestore(websiteQuery);
</script>

Другие вопросы по теме