从firebase数据库中检索计算平均值

Posted

技术标签:

【中文标题】从firebase数据库中检索计算平均值【英文标题】:Retrieve from firebase database calculating average 【发布时间】:2017-05-17 11:23:18 【问题描述】:

我正在创建一个 ios 应用程序,它使用每个地点的地名和评级。我已经让这件事发挥作用了。我的意思是,我将数据保存到我的数据库中,并且我也可以读取它们。唯一的问题是,当我阅读它们时,我希望它们通过计算每个位置的平均值来加载到我的 tableviewcell 上。查看屏幕截图,如果您有不明白的地方,请让我编辑答案。

表格视图

Firebase

将数据加载到 tableview 的我的代码

import UIKit
import FirebaseDatabase

class PlacesTableViewController: UITableViewController 

    //MARK: Properties
    @IBOutlet weak var placesTableView: UITableView!
    var dbRef:FIRDatabaseReference?
    var places = [Places]()
    private var loadedLabels = [String: String]()
    private var loadedRatings = [String: Int]()
    override func viewDidLoad()
    
        super.viewDidLoad()

        dbRef = FIRDatabase.database().reference()

        // Loads data to cell.
        loadData()
    
    override func numberOfSections(in tableView: UITableView) -> Int
    
        return 1
    

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
       
        //return the number of rows
        return places.count
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    
        // Table view cells are reused and should be dequeued using a cell identifier.


        guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? PlacesTableViewCell  else 
            fatalError("The dequeued cell is not an instance of PlacesTableView Cell.")
        

        let place = places[indexPath.row]

        cell.placeLabel.text = place.name
        cell.ratingControl.rating = place.rating

        return cell

    
    private func loadData()
    
        dbRef!.observe(.childAdded, with: 
            (placeSnapshot) in
            //print("Adding place \(placeSnapshot.key)...")

            let labels = placeSnapshot.childSnapshot(forPath: "placeLabel")

            for (key, label) in labels.value as! [String: String] 
                self.updatePlace(key, label: label)
            
            let ratings = placeSnapshot.childSnapshot(forPath: "rating")
            for (key, rating) in ratings.value as! [String: Int] 
                self.updatePlace(key, rating: rating)
            
        )
 

    private func updatePlace(_ key: String, label: String? = nil, rating: Int? = nil)
    
        if let label = label 
            loadedLabels[key] = label

        
        if let rating = rating 
            loadedRatings[key] = rating
        
        guard let label = loadedLabels[key], let rating = loadedRatings[key] else 
            return
        
        if let place = Places(name: label, rating: rating) 
            places.append(place)
            placesTableView.reloadData()
        
    


快速定位

import UIKit

class Places 

    //MARK: Properties

    var name: String
    var rating: Int

    //MARK:Types

    struct PropertyKey 
        static let name = "name"
        static let rating = "rating"
    

    //MARK: Initialization

    init?(name: String, rating: Int) 
        // Initialize stored properties.
        self.name = name
        self.rating = rating

        // Initialization should fail if there is no name or if the rating is negative.
        // The name must not be empty
        guard !name.isEmpty else 
            return nil
        

        // The rating must be between 0 and 5 inclusively
        guard (rating >= 0) && (rating <= 5) else 
            return nil
        

    


【问题讨论】:

不清楚你在问什么。您是否正在尝试获得某个地方的平均评分?如果是这样,那就是读取每个地方的评分节点并平均子节点的值;(2 + 4 + 5)/ 3? 有错误信息吗?是否有一些代码不能按预期的方式工作?与其向我们展示你所有的代码,不如选择一件阻碍你的具体事情并描述它。例如,不了解火力基地的人可能会提供帮助。缩小问题范围。 @Jay 是的,这就是我想要的。 @Mozahler 在另一个函数中出现错误,而不是读取值。当用户添加新地点时,tableview 尝试更新并崩溃,但如果他重新打开应用程序,则“新地点”会正确显示在 tableview 上。这是我的previous 问题中的一个问题。 那么是您的代码崩溃的问题,还是您需要知道如何读取节点并找到一系列数字的平均值的问题? 【参考方案1】:

据我了解,您希望为您的应用程序设置一个四舍五入的双精度数,而不是双精度数。只需更改 loadData() 函数中的代码,它就会为您工作。你也可以像以前一样打电话给updatePlace()。请批准杰伊的回答,他编写了代码。

private func loadData()

    dbRef!.observe(.childAdded, with: 
        (placeSnapshot) in
    let parentRef = self.dbRef?.child(placeSnapshot.key)
    let ratingRef = parentRef?.child("rating")
    ratingRef?.observe(.value, with:  snapshot in
        let count = snapshot.childrenCount
        var total: Double = 0.0
        for child in snapshot.children 
            let snap = child as! FIRDataSnapshot
            let val = snap.value as! Double
            total += val
        
        let average = total/Double(count)
        print("Average for \(placeSnapshot.key) = \(Int(round(average)))")

        self.updatePlace("" , label: placeSnapshot.key, rating: Int(round(average)))

    )
    )


【讨论】:

为什么第一个里面有第二个观察? .childAdded 将返回节点中的所有内容,因此评分将已经在快照中。 这将返回每个地方的平均评分。例如,Markiz 的平均值 = 3 Paradosiako 的平均值 - 全景图 = 3 不是我的意思。结果节点包含在 placeSnapshot 中,因此没有理由再次访问数据库来获取相同的数据。 @Jay 好的明白了 :) !【参考方案2】:

这是一个非常冗长的答案,但它会遍历评级节点的子节点并计算平均值

let parentRef = self.dbRef.child("Paradosiako - Panorama")

let ratingRef = parentRef.child("rating") // rating node
ratingRef.observe(.value, with:  snapshot in
    let count = snapshot.childrenCount
    var total: Double = 0.0
    for child in snapshot.children 
        let snap = child as! FIRDataSnapshot
        let val = snap.value as! Double
        total += val
    
    let average = total/Double(count)
    print(average)
)

编辑

要遍历所有位置并获取平均值,代码如下

let placesRef = self.dbRef.child("akapnapp")

placesRef.observeSingleEvent(of: .value, with:  snapshot in

    for child in snapshot.children 

        let placeSnap = child as! FIRDataSnapshot
        let ratingsSnap = placeSnap.childSnapshot(forPath: "rating")

        let count = ratingsSnap.childrenCount
        var total: Double = 0.0
        for child in ratingsSnap.children 
            print(child)
            let snap = child as! FIRDataSnapshot
            let val = snap.value as! Double
            total += val
        
        let average = total/Double(count)
        print(average)
    
)

并且显示代码的输出正常工作。我的子节点在问题中被命名为 a,b,c 而不是 childByAutoId,但无论哪种方式都可以。

Snap (a) 3
Snap (b) 3
3.0
Snap (a) 2
Snap (b) 4
Snap (c) 5
3.67

【讨论】:

感谢您的回答,但是编译器说PlacesTableViewController has no member 'ref' self.ref 是对您的 firebase 数据库的引用,即 ref = FIRDatabase.database().reference()。在您的情况下,它似乎被称为 dbRef。更新了答案以反映这一点。 @Jay 她需要对她数据库中的每个地方都这样做。 @AlexAndreadis 谢谢。我知道这一点,但认为 OP 可以从我的代码 sn-p 中推断出来。更新了竞争力的答案。 @RoulaChiouma 我更新了我的答案并为你编写了代码。它将遍历主数据库节点中的所有位置并计算平均值。

以上是关于从firebase数据库中检索计算平均值的主要内容,如果未能解决你的问题,请参考以下文章

试图从 firebase Swift 获取数据

如何从 Firebase 实时数据库中检索特定数据?

无法从 firebase 数据库中检索数据(云功能)

从firebase实时数据库IOS Swift中检索数据

无法从短动态链接中检索数据 - Firebase

Firebase:从实时数据库中检索 childByAutoID