J'utilise firebase / firestore et je cherche un moyen de retourner la promesse d'un instantané.

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

Dans un autre fichier que j'ai fait

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

Je reçois les erreurs

Erreur: échec de Query.onSnapshot: appelé avec des arguments non valides.

TypeError: _firebaseService2.default.unsubscribe n'est pas une fonction

Si je fais de cette façon

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

Je reçois

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

En plus, quand je fais de cette façon

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

// autre fichier

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

Il n'écoute pas pour changer en firebase, signifie que si je change en firebase ce n'est pas mettre à jour ou changer la taille ..

---- fonction firestore --- J'ai essayé de faire une fonction firestore qui se déclenche à chaque mise à jour du nœud UserStatus mais cela prend quelques secondes et cela me ralentit.

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.log(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);
    });
});

Fonction pour calculer et mettre à jour le nombre d'utilisateurs en ligne

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 })
    })
})
3
Manspof 17 avril 2018 à 14:24

3 réponses

Meilleure réponse

Un Promise en JavaScript peut résoudre (ou rejeter) une seule fois. Un onSnapshot d'autre part peut donner des résultats plusieurs fois. C'est pourquoi onSnapshot ne retourne pas de promesse.

Dans votre code actuel, vous vous retrouvez avec un écouteur suspendu à status_database_ref. Puisque vous ne faites rien avec les données, il est inutile de continuer à les écouter.

Au lieu d'utiliser onSnapshot, utilisez get:

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

Ou dans votre approche originale:

onlineUsers(){
    return this.status_database_ref.where('state','==','online').get();
}
6
Frank van Puffelen 17 avril 2018 à 13:33

J'ai trouvé un moyen de le faire

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

componentDidMount(){

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

}
-1
Manspof 17 avril 2018 à 11:49

Je sais qu'il est trop tard mais voici ma solution en utilisant TypeScript et Javascript.

MANUSCRIT

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(); });
};
0
Abhishek Tomar 26 oct. 2019 à 02:32