如何在 Swift 中的 Firebase 查询中应用多个过滤器?

问题描述 投票:0回答:2

我正在尝试开发像出租车预订这样的应用程序并在 Firebase 上存储数据。

但是,我在从 Firebase 查询 RideDetail(History) 数据时遇到问题。

我想以分页形式获取特定“customer_id”的ride_detail。

我的 Firebase 数据结构:

{
  "ride_details": {
    "NuEoP2WNPwigsbY1FQy9M150131918189233": {
      "customer_id": "tstebwLlf4OCRdWhNKO9XCO08xY2",
      "destination_address": "New Ranip\nNew Ranip\nAhmedabad\nGujarat 380081\nIndia",
      "destination_lang": 72.55924470000001,
      "destination_latg": 23.0930152,
      "discount": "10%",
      "driver_id": "cIyZQIJ7tsdvF1a9KpRrKucF2o62",
      "drop_time": "2017-07-29 09:12:21 +0000",
      "fare": "13.16 Rs.",
      "payment_time": 150149034812771,
      "pickup_time": "2017-07-29 09:10:38 +0000",
      "priceperkm": "10.00 Rs.",
      "ride_confirm_time": "2017-07-29 09:06:21 +0000",
      "source_address": "Vastrapur\nVastrapur\nAhmedabad\nGujarat\nIndia",
      "source_lang": 72.5293244,
      "source_latg": 23.0350073,
      "tax": "10%"
    },
    "RH0oZ0Ypbkur3wJM3HMvM150147833457957": {
      "customer_id": "aYQFbwLlf4OCRdWhNKO9XCO08xY2",
      "destination_address": "Sarovar Park Plaza Hotels and Resorts Private Limted\nNo 1\nSector 10\nCBD Belapur\nWadala West\nWadala\nMumbai\nMaharashtra 400614\nIndia",
      "destination_lang": 72.8561644,
      "destination_latg": 19.0176147,
      "discount": 0,
      "driver_id": "cIyZQIJ7tsdvF1a9KpRrKucF2o62",
      "drop_time": "",
      "fare": 0,
      "payment_time": 150149034812772,
      "pickup_time": "",
      "priceperkm": 0,
      "ride_confirm_time": "2017-07-31 05:18:54 +0000",
      "source_address": "Smokin Joe's Fresh Pizza\nShop No. 2\n3\nGround Floor\nAbhiman II\nWadala West\nThane West\nMumbai\nMaharashtra 400602\nIndia",
      "source_lang": 72.8561644,
      "source_latg": 19.0176147,
      "tax": 0
    }
  }
}

这里的“ payment_time”是付款完成时的时间戳。

我想要的回应是这样的:

{
    "RH0oZ0Ypbkur3wJM3HMvM150147833457957": {
      "customer_id": "aYQFbwLlf4OCRdWhNKO9XCO08xY2",
      "destination_address": "Sarovar Park Plaza Hotels and Resorts Private Limted\nNo 1\nSector 10\nCBD Belapur\nWadala West\nWadala\nMumbai\nMaharashtra 400614\nIndia",
      "destination_lang": 72.8561644,
      "destination_latg": 19.0176147,
      "discount": 0,
      "driver_id": "cIyZQIJ7tsdvF1a9KpRrKucF2o62",
      "drop_time": "",
      "fare": 0,
      "payment_type": 150149034812772,
      "pickup_time": "",
      "priceperkm": 0,
      "ride_confirm_time": "2017-07-31 05:18:54 +0000",
      "source_address": "Smokin Joe's Fresh Pizza\nShop No. 2\n3\nGround Floor\nAbhiman II\nWadala West\nThane West\nMumbai\nMaharashtra 400602\nIndia",
      "source_lang": 72.8561644,
      "source_latg": 19.0176147,
      "tax": 0
    },
    "1trcf0Ypbkur3wJM3HMvM150147833457957": {
      "customer_id": "aYQFbwLlf4OCRdWhNKO9XCO08xY2",
      "destination_address": "Sarovar Park Plaza Hotels and Resorts Private Limted\nNo 1\nSector 10\nCBD Belapur\nWadala West\nWadala\nMumbai\nMaharashtra 400614\nIndia",
      "destination_lang": 72.8561644,
      "destination_latg": 19.0176147,
      "discount": 0,
      "driver_id": "cIyZQIJ7tsdvF1a9KpRrKucF2o62",
      "drop_time": "",
      "fare": 0,
      "payment_type": 150149034812778,
      "pickup_time": "",
      "priceperkm": 0,
      "ride_confirm_time": "2017-07-31 05:18:54 +0000",
      "source_address": "Smokin Joe's Fresh Pizza\nShop No. 2\n3\nGround Floor\nAbhiman II\nWadala West\nThane West\nMumbai\nMaharashtra 400602\nIndia",
      "source_lang": 72.8561644,
      "source_latg": 19.0176147,
      "tax": 0
    } 
}

我想要特定“customer_id”的前 10 条记录,这些记录是我在orderedBy“ payment_time”查询中传递的。我也想做同样的分页。即在第二次查询调用中,它必须返回 11-20 条记录,依此类推。

ios swift firebase firebase-realtime-database pagination
2个回答
3
投票

问题和评论有一些不同的标准,但让我在高层次上解决它;

第一个答案是:Firebase 不能查询一个孩子的值,然后由另一个孩子订购。

简单查询功能表示:

let query = ridesRef.queryOrdered(byChild: "cust_id").queryEqual(toValue: "cust id 4")

要完成该任务,请查询所需的子数据,在本例中是所有客户 id 4 的节点,然后在代码中进行排序。这是一个例子

class RideClass {
    var key = ""
    var cust_id = ""
    var pay_time = ""
    
    init(key: String, cust_id: String, pay_time: String) {
        self.key = key
        self.cust_id = cust_id
        self.pay_time = pay_time
    }
}

var rideArray = [RideClass]()

func populateRideArray() {
    let usersRef = self.ref.child("ride_details")
    let query = usersRef.queryOrdered(byChild: "cust_id").queryEqual(toValue: "cust id 4") 
    query.observeSingleEvent(of: .value, with: { snapshot in 
        for child in snapshot.children {
            let snap = child as! DataSnapshot
            let dict = snap.value as! [String: Any]
            let key = snap.key
            let custId = dict["cust_id"] as! String
            let payTime = dict["pay_time"] as! String
            let ride = RideClass(key: key, cust_id: custId, pay_time: payTime)
            self.rideArray.append(ride)
        }
        
        for ride in self.rideArray {  //unsorted example
            print(ride.pay_time)
        }
        
        self.rideArray.sort { $0.pay_time < $1.pay_time } //sort
        
        for ride in self.rideArray {  //sorted example
            print(ride.pay_time)
        }
    })
}

在此示例中,我们创建一个 RideClass 来存储一些有关行程的信息,然后创建一个可用作 tableView 数据源的行程数组。

然后查询 cust id 4 的所有游乐设施。我们有一个循环来显示未排序的检索内容,然后是这个小宝石

self.rideArray.sort { $0.pay_time < $1.pay_time }

按 pay_time 对乘车数组进行排序,这回答了问题。

假设有 100,000 个骑行子节点。加载所有这些数据并在代码中排序可能对内存来说是一个挑战。你做什么?

我们利用复合价值;除了 cust_id 和 pay_time 的子节点之外,我们还包括 id_time。这是一个可能的结构:

  "ride_details" : {
    "ride_0" : {
      "cust_id" : "cust id 4",
      "id_time" : "cust id 4_172200",
      "pay_time" : "172200"
    },
    "ride_1" : {
      "cust_id" : "cust id 2",
      "id_time" : "cust id 2_165500",
      "pay_time" : "165500"
    },
    "ride_2" : {
      "cust_id" : "cust id 1",
      "id_time" : "cust id 1_182300",
      "pay_time" : "182300"
    },
    "ride_3" : {
      "cust_id" : "cust id 3",
      "id_time" : "cust id 3_131800",
      "pay_time" : "131800"
    },
    "ride_4" : {
      "cust_id" : "cust id 4",
      "id_time" : "cust id 4_132200",
      "pay_time" : "132200"
    }
  },

然后一些代码以正确的顺序读取 cust id 4 个节点

    let ridesRef = self.ref.child("ride_details")
    let query = ridesRef.queryOrdered(byChild: "id_time")
                        .queryStarting(atValue: "cust id 4_")
                        .queryEnding(atValue: "cust id 4_\\uf8ff")
    query.observeSingleEvent(of: .value, with: { snapshot in
        for child in snapshot.children {
            let snap = child as! DataSnapshot
            let dict = snap.value as! [String: Any]
            let key = snap.key
            let custId = dict["cust_id"] as! String
            let payTime = dict["pay_time"] as! String
            let ride = RideClass(key: key, cust_id: custId, pay_time: payTime)
            self.rideArray.append(ride)
        }
        
        for ride in self.rideArray {  //unsorted example
            print(ride.pay_time)
        }
    })

有两点需要注意:

必须迭代快照以维护子序列

“\uf8ff”是 Unicode 中代码级别非常高的字符 - 因为它包含所有前面的字符。

编辑:2024-06

You may need to use "\u{F8FF}" instead of "\\uf8ff"

0
投票

有两种基本方法可能适合您的要求:

  1. 构造一个按

    payment_time
    排序的查询,限制为仅包含前 10 条记录,然后保存对第 10 条记录的引用,以便您可以使用
    queryStartingAtValue
    过滤器进行后续分页调用。

  2. 设置一个 Firebase 云函数,其中数据库触发器监听

    payment_time
    节点,这样每次用数据库中的值更新您的空字符串时,您都会转换数据,以便以一种使其变得微不足道的方式进行组织在这里消费以满足您的需求。例如 - 我将按照如下所示的路径组织新数据:
    customer_ride_details/{{customer_id}}/{{ride_id}}
    。因为当您用时间戳替换
    payment_time
    空字符串时就会触发该函数。钥匙应该已经订购好供您使用。您仍然需要像我们对选项 1 所做的那样管理分页。

© www.soinside.com 2019 - 2024. All rights reserved.