2017-08-11 1 views
1

Mit einer Anwendung, in der ein Benutzer andere Benutzerbilder bewerten kann, möchte ich die Gesamtzahl der Stimmen, die ein Benutzer erhalten hat, zählen. Der beste Weg, um dieses Ziel mit Firebase zu erreichen, besteht darin, das 'onWrite' -Ereignis zu kontrollieren und den Zähler für jeden Benutzer manuell zu aktualisieren, wenn er eine Stimme erhält.Firebase Cloud-Funktionen - Aktualisieren eines Werts mit onWrite-Ereignis

Das Problem, das ich mit dem folgenden Code gefunden habe, ist, dass die 'votesCount' nicht genau auf das erste 'onWrite' -Ereignis aktualisiert wird, aber im nächsten 'onWrite' -Ereignis mit der Rate für den vorherigen Benutzer aktualisiert wird . Warum passiert dies? Ist das ein guter Ansatz für eine Abstimmungsanwendung?

Der Zweck der folgenden Methode ist es, zu überprüfen, ob der gewählte Benutzer 'votes_count' hat, falls wahr, füge den neuen Wert dem alten hinzu, im gegenteiligen Fall füge einfach den neuen Wert hinzu.

exports.updateVotesCount = functions.database.ref('/votes/{id}').onWrite(event => { 
    const data = event.data.val(); 
    var votesCount = admin.database().ref('/profiles/' + data.to).child('votes_count'); 
    votesCount.once('value').then(function(snapshot) { 
     if (snapshot.val()) { 
     votesCount.set(snapshot.val() + data.rate); 
     } else { 
     votesCount.set(data.rate); 
     } 
    }); 
}); 

Dies ist der Aspekt der Datenstruktur, die ich verwende:

{ 
    profiles: [ 
     userId: { 
     name: "...", 
     image: "...", 
     votes_count: "..." 
     }, 
     ... 
    ], 
    votes: [ 
     voteId: { 
     from: "userId", 
     to: "userId", 
     rate: n 
     }, 
     ... 
    ] 

Antwort

1

Nein, Sie transaction zum Erhöhen Werte verwenden soll. Sie haben auch keinen Wert zurückgegeben. Ihre Funktion hat daher eine Zeitüberschreitung. Die Rückgabe ist in Cloud-Funktionen erforderlich.

Der Code sollte wie folgt aussehen:

exports.updateVotesCount = functions.database.ref('/votes/{id}').onWrite(event => { 
    const data = event.data.val(); 
    return admin.database().ref('/profiles/' + data.to).child('votes_count').transaction(function(votes) { 
    if (event.data.exists()){ //If there is a onCreate action (user adds a vote) or use your own snapshot.val() 
      return (votes || 0) + 1; //providing a default "0" value if there is no value 
     }else{ // if there is a onDelete action (user removes avote) 
      return (votes || 1) - 1; //providing a default "1" value if there is no value 
    } 
    }) 
}) 

Ich konnte aber nicht den Code testen, aber ich denke, es sollte funktionieren ... Beachten Sie, dass der Wert erhöht wird, wenn der Benutzer einen Wert an die angegebene fügt Pfad, und der Wert wird verringert, wenn der Benutzer den angegebenen Pfad entfernt, aber Sie können dies einfach ändern, wie ich in meinem Beispiel gesagt habe.

+0

Vielen Dank, dies scheint ein großer Schritt zu sein, jetzt kann ich es korrekt aktualisieren, indem Sie Transaktionen verwenden, der einzige Punkt ist, dass die Funktion "Fehler Serialisierung Rückgabewert: TypeError: Konvertieren von kreisförmigen Struktur zu JSON" in der Konsole. Ich weiß nicht warum, da 'Stimmen' immer ein Gleitkommawert sein sollten. –

+1

@ AlejandroMorán O Junge, wenn Sie diesen Fehler beheben können, bist du mein Held. Ich habe es hier auf Github gefragt: https://github.com/firebase/functions-samples/issues/193 und es gibt einen Workaround ... Ich denke, es ist ein Fehler in Firebase, der bald behoben werden sollte. –

+0

Ja, es scheint, es ist ein Firebase-Bug nach dieser Antwort: https://github.com/firebase/functions-samples/issues/193#issuecomment-317884437 Rückgabewert ist ein TransactionResult und kann nicht serialisiert werden, gibt es ein Workaround dafür. –

Verwandte Themen