Firebase возвращает обещание снэпшота

Я использую firebase / firestore и ищу способ вернуть обещание снимка.

onlineUsers(){
     // i want to return onSnapshot
    return this.status_database_ref.where('state','==','online').onSnapshot();
}

в другом файле я сделал

  componentDidMount(){
    // this.unsubscribe = this.ref.where('state','==','online').onSnapshot(this.onCollectionUpdate) 
    firebaseService.onlineUsers().then(e=>{
        console.info(e)
    })
}

Я получаю ошибки

Error: Query.onSnapshot failed: Called with invalid arguments.

TypeError: _firebaseService2.default.unsubscribe is not a function

если я сделаю так

onlineUsers(){
   return  this.status_database_ref.where('state','==','online').onSnapshot((querySnapshot)=>{
        return querySnapshot
    }) 
}

я получил

TypeError: _firebaseService2.default.onlineUsers(...).then is not a function

Кроме того, когда я так делаю

   this.unsubscribe = firebaseService.onlineUsers().then((querySnapshot)=>{
        console.info(querySnapshot.size)
        this.setState({count:querySnapshot.size})
    })

// другой файл

 onlineUsers(callback) {
    return this.status_database_ref.where('state', '==', 'online').get()
}

он не слушает изменения в firebase, это означает, что если я изменю в firebase, он не обновит или не изменит размер ..

---- функция firestore --- Я попытался сделать функцию firestore, которая запускается каждый раз, когда узел UserStatus обновляется, но это занимает несколько секунд и для меня это медленно.

module.exports.onUserStatusChanged = functions.database
.ref('/UserStatus/{uid}').onUpdate((change, context) => {
    // Get the data written to Realtime Database
    const eventStatus = change.after.val();

    // Then use other event data to create a reference to the
    // corresponding Firestore document.
    const userStatusFirestoreRef = firestore.doc(`UserStatus/${context.params.uid}`);


    // It is likely that the Realtime Database change that triggered
    // this event has already been overwritten by a fast change in
    // online / offline status, so we'll re-read the current data
    // and compare the timestamps.
    return change.after.ref.once("value").then((statusSnapshot) => {
        return statusSnapshot.val();
    }).then((status) => {
        console.info(status, eventStatus);
        // If the current timestamp for this data is newer than
        // the data that triggered this event, we exit this function.
        if (status.last_changed > eventStatus.last_changed) return status;

        // Otherwise, we convert the last_changed field to a Date
        eventStatus.last_changed = new Date(eventStatus.last_changed);

        // ... and write it to Firestore.
        //return userStatusFirestoreRef.set(eventStatus);
        return userStatusFirestoreRef.update(eventStatus);
    });
});

функция для подсчета и обновления количества онлайн-пользователей

module.exports.countOnlineUsers = functions.firestore.document('/UserStatus/{uid}').onWrite((change, context) => {

    const userOnlineCounterRef = firestore.doc('Counters/onlineUsersCounter');

    const docRef = firestore.collection('UserStatus').where('state', '==', 'online').get().then(e => {
        let count = e.size;
        return userOnlineCounterRef.update({ count })
    })
})
Поведение ключевого слова "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) для оценки ваших знаний,...
4
0
12 388
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Я нашел способ сделать это

onlineUsers(callback){
   return  this.status_database_ref.where('state','==','online').onSnapshot((querySnapshot)=>{
        callback(querySnapshot.size)
    }) 
}

componentDidMount(){

    this.unsubscribe = firebaseService.onlineUsers(this.onUpdateOnlineUsers);
    console.info(this.unsubscribe)
}
onUpdateOnlineUsers(count){
    this.setState({count})
}
componentWillUnmount(){
    this.unsubscribe();

}
Ответ принят как подходящий

Promise в JavaScript может разрешить (или отклонить) ровно один раз. С другой стороны, onSnapshot может давать результаты несколько раз. Вот почему onSnapshot не возвращает обещание.

В вашем текущем коде у вас остался болтающийся слушатель status_database_ref. Поскольку вы ничего не делаете с данными, постоянно их слушать бесполезно.

Вместо использования onSnapshot, использовать get:

onlineUsers(callback){
    this.status_database_ref.where('state','==','online').get((querySnapshot)=>{
        callback(querySnapshot.size)
    }) 
}

Или в вашем оригинальном подходе:

onlineUsers(){
    return this.status_database_ref.where('state','==','online').get();
}

откровенно говоря, я отредактировал свой пост. Я поступил по-твоему, и я не слушаю смену в пожарном магазине. если я вручную изменяю состояние на офлайн, размер, который я получаю, не меняется, и я вижу, что он снова вызывает запрос

Manspof 17.04.2018 15:44

Ни код в вашем вопросе, ни в вашем ответе не отслеживают изменений. И onSnapshot, и get() немедленно вернут текущие документы, соответствующие запросу. Код, который я привел в своем ответе, покажет вам, какие пользователи сейчас в сети. На данный момент мне неясно, чего пытается достичь ваш код (он начинает ощущаться как XY проблема).

Frank van Puffelen 17.04.2018 16:09

Я хочу послушать сборник «статус». если пользователь регистрируется на firebase, он меняет свой статус с uid на «онлайн», когда он закрывает приложение, он меняет свой статус на «офлайн». Я хочу узнать текущий размер онлайн-пользователей. если пользователь в приложении, а другой пользователь закрывает приложение, поэтому он должен показывать реальный счет и количество обновлений

Manspof 17.04.2018 16:12

эй, откровенно, у тебя есть какое-нибудь решение?

Manspof 17.04.2018 21:42

Я, честно говоря, до сих пор не понимаю, какова здесь цель. Или, может быть, я не могу понять, как это перевести в код. Чем то, что теперь возвращает ваш (или мой) запрос, отличается от того, что вам нужно?

Frank van Puffelen 18.04.2018 01:18

ваш запрос работает хорошо, НО, когда я нахожусь в приложении и кто-то новый меняется на «онлайн» или «офлайн», счетчик не меняется. счетчик не рассчитывается заново, он не прислушивается к изменениям! Кроме того, я отредактировал свой пост и сделал это с помощью функции firestore, но для его обновления требуется 3-5 секунд, и это медленно для меня

Manspof 18.04.2018 15:35

Я знаю, что уже слишком поздно, но вот мое решение с использованием TypeScript и Javascript.

TYPESCRIPT

const _db=firebase.firestore;
const _collectionName = "users";

    onDocumentChange = (
    document: string,
    callbackSuccess: (currentData: firebase.firestore.DocumentData, source?: string | 'Local' | 'Server') => void,
    callbackError?: (e: Error) => void,
    callbackCompletion?: () => void
) => {
    this._db.collection(this._collectionName).doc(document).onSnapshot(
        {
            // Listen for document metadata changes
            includeMetadataChanges: true
        },
        (doc) => {
            const source = doc.metadata.hasPendingWrites ? 'Local' : 'Server';
            callbackSuccess(doc.data(), source);
        },
        (error) => callbackError(error),
        () => callbackCompletion()
    );
};

JAVASCRIPT (ES5)

var _this = this;
onDocumentChange = function (document, callbackSuccess, callbackError, callbackCompletion) {
    _this._db.collection(_this._collectionName).doc(document).onSnapshot({
        // Listen for document metadata changes
        includeMetadataChanges: true
    }, function (doc) {
        var source = doc.metadata.hasPendingWrites ? 'Local' : 'Server';
        callbackSuccess(doc.data(), source);
    }, function (error) { return callbackError(error); }, function () { return callbackCompletion(); });
};

Хотел бы я предоставить 2 голоса: один за правильное решение и один за решение на TypeScript!

Patrick 27.08.2020 07:10

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