0

私は何時間もコードとノートを見てきました。私はfirebaseを備えた迅速なアプリケーションでオブジェクトをupvotingとdownvotingするのに役立つドキュメントを見つけるのに苦労しています。Upvote/Downvoteシステム内のFirebase経由で

私は写真のギャラリーを持っており、画像にinstagramスタイルのupvoteを追加しようとしています。ユーザーはすでにfirebase authでログオンしているので、ユーザーIDを持っています。

私は方法を理解するのに苦労し、firebaseにどのようなルールを設定する必要がありますか。

ご協力いただければ幸いです。

答えて

9

SwiftFirebaseを使用して、ソーシャルネットワーキングアプリケーションImpetherでこのような機能を実装した方法について説明します。

upvotingとdownvotingは類似しているので、私はupvotingだけを説明します。

一般的な考え方は、カウンタが関連する画像データに対応するノードにupvotesカウンタを直接格納し、トランザクションの書き込みを使用してカウンタ値を更新してデータの不一致を避けることです。

例えば、あなたが$imageId、特定の画像を識別するために使用される固有のIDであるパス/images/$imageId/、で単一の画像データを格納すると仮定する - それは、iOS用Firebaseに含まれる機能childByAutoIdによって例えば生成することができます。そして、そのノードにおいて単一の光に対応するオブジェクトは、次のようになります。私たちが何をしたいか

$imageId: { 
    'url': 'http://static.example.com/images/$imageId.jpg', 
    'caption': 'Some caption', 
    'author_username': 'foobarbaz' 
} 

すると、このノードにupvoteカウンタを追加することで、それは次のようになります。

$imageId: { 
    'url': 'http://static.example.com/images/$imageId.jpg', 
    'caption': 'Some caption', 
    'author_username': 'foobarbaz', 
    'upvotes': 12, 
} 

あなたがいる場合には(おそらくユーザーがそれをアップロードしたときに)新しい画像を作成したら、達成したいことに応じて、アップカウントカウンタ値を0またはその他の定数で初期化することができます。

特定のupvotesカウンタを更新する場合は、値の矛盾を避けるためにトランザクションを使用する必要があります(これは、複数のクライアントが同時にカウンタを更新する場合に発生する可能性があります)。

幸い、トランザクションを処理することはFirebaseに書き込み、Swiftは超簡単です:

func upvote(imageId: String, 
      success successBlock: (Int) -> Void, 
      error errorBlock:() -> Void) { 

    let ref = Firebase(url: "https://YOUR-FIREBASE-URL.firebaseio.com/images") 
     .childByAppendingPath(imageId) 
     .childByAppendingPath("upvotes") 

    ref.runTransactionBlock({ 
     (currentData: FMutableData!) in 

     //value of the counter before an update 
     var value = currentData.value as? Int 

     //checking for nil data is very important when using 
     //transactional writes 
     if value == nil { 
      value = 0 
     } 

     //actual update 
     currentData.value = value! + 1 
     return FTransactionResult.successWithValue(currentData) 
     }, andCompletionBlock: { 
      error, commited, snap in 

      //if the transaction was commited, i.e. the data 
      //under snap variable has the value of the counter after 
      //updates are done 
      if commited { 
       let upvotes = snap.value as! Int 
       //call success callback function if you want 
       successBlock(upvotes) 
      } else { 
       //call error callback function if you want 
       errorBlock() 
      } 
    }) 
} 

上記スニップは、ほぼ正確に、実際に私たちが生産に使用するコードです。私はそれがあなたを助けることを願っています:)

+0

ありがとうございます!Firebase SDKのアップデートでは、FMutableDataはFIRMutableDataになり、FTransactionResultはFIRTransactionResultになります – PAD

+1

これは非常に参考になりました。 –

+0

ユーザーがすでに好きだった場合の解決策はありません。そしてそれは+ to - に変わるだけではありません。 userIDを保存し、現在のuserIDと比較する必要があります。これははるかに複雑です。 –

1

私は素人ではありませんが、this stackoverflow questionはあなたの答えのほとんどを持っていると思います。

次に、投票を行うか否かに基づいてトランザクションから正しい値を返すために、2つのif文を使用します。

1

私は非常に驚いていましたが、元のドキュメントからthis codeは魅力のように動作します。それには1つの欠点があります.Jsonは、好きな人がたくさんいるとかなり大きくなります。

FirebaseService.shared.databaseReference 
      .child("items") 
      .child(itemID!) 
      .runTransactionBlock({ (currentData: MutableData) -> TransactionResult in 
       if var item = currentData.value as? [String : AnyObject] { 
       let uid = SharedUser.current!.id 

       var usersLikedIdsArray = item["liked_who"] as? [String : Bool] ?? [:] 
       var likesCount = item["likes"] as? Int ?? 0 

        if usersLikedIdsArray[uid] == nil { 
         likesCount += 1 
         usersLikedIdsArray[uid] = true 
         self.setImage(self.activeImage!, for: .normal) 
         self.updateClosure?(true) 
        } else { 
         likesCount -= 1 
         usersLikedIdsArray.removeValue(forKey: uid) 
         self.setImage(self.unactiveImage!, for: .normal) 
         self.updateClosure?(false) 
        } 

       item["liked_who"] = usersLikedIdsArray as AnyObject? 
       item["likes"] = likesCount as AnyObject? 

       currentData.value = item 

       return TransactionResult.success(withValue: currentData) 
      } 
      return TransactionResult.success(withValue: currentData) 
     }) { (error, committed, snapshot) in 
      if let error = error { 
       self.owner?.show(error: error) 
      } 
     } 
関連する問題