Firebase数据结构查询
Firebase data structure query
阅读文档后,他们建议不要使用嵌套数据结构。我认为这是处理我的数据的最佳方式,但我不确定如何将 tripId 添加到酒店集合中。
我的另一个选择是让用户为每个酒店条目输入“BOL”...我对该方法的问题是如何查询日期以查看与“行程”匹配的所有酒店?
编辑::::::::
我想要完成的是,当用户选择一次旅行时,它会运行一个查询并显示与该旅行相关的酒店的所有夜晚总数。
users:
- gCFiwSLwBeg87N6GfeofFxIAZyi2
- UID: gCFiwSLwBeg87N6GfeofFxIAZyi2
- firstName: "James"
- email: "a@email.com"
trips:
- "random document id"
- bol: "1234567"
- startDate: "1/3/2022"
- destination: "Sacramento, CA"
- userID: "Users UID"
- foodTotal: "100"
- hotelTotal: "240"
- "random document id"
- bol: "256976"
- startDate: "2/5/2022"
- destination: "Orlando, FL"
- userID: "Users UID"
- foodTotal: "150"
- hotelTotal: "400"
hotels:
- "random document id"
- tripId: ?
- date: "1/4/2022"
- destination: "Sacramento, CA"
- userID: "Users UID"
- name: "Hotel Inn"
- cost: "120"
- "random document id"
- tripId: ?
- date: "1/5/2022"
- destination: "Sacramento, CA"
- userID: "Users UID"
- name: "Hotel Inn"
- cost: "120"
这是我目前用来将酒店添加到 firebase 的函数。
class FirebaseHotelRepository: HotelRepositoryProtocol {
private let db = Firestore.firestore()
func addHotel(hotel: Hotel, completion: @escaping (Result<Hotel?, Error>) -> Void) {
do {
var addedHotel = hotel
addedHotel.userId = Auth.auth().currentUser?.uid
let _ = try db.collection("hotels").addDocument(from: addedHotel)
} catch {
fatalError("Unable to encode trip: \(error.localizedDescription)")
}
}
}
class AddHotelViewModel: ObservableObject {
private let repo: HotelRepositoryProtocol
var name: String = ""
var location: String = ""
var date = Date()
var cost: String = ""
@Published var saved: Bool = false
init(repo: HotelRepositoryProtocol) {
self.repo = repo
}
func addHotel() {
let hotel = Hotel(bol: bol,
name: name,
location: location,
date: date,
cost: cost,
color: UIColor(color).hexStringFromColor())
repo.addHotel(hotel: hotel) { result in
switch result {
case .success(let savedHotel):
DispatchQueue.main.async {
self.saved = savedHotel == nil ? false : true
}
case .failure(let error):
print(error.localizedDescription)
}
}
}
}
从这个documentation:
In some cases, it can be useful to create a document reference with an auto-generated ID, then use the reference later. For this use case, you can call doc():
这里有一个示例代码,您可以参考:
let trips = db.collection("trips").addDocument(data: [
// trips' data
])
// This will append tripId to the `addedHotel`
addedHotel["tripId"] = trips.documentID
let hotels = db.collection("hotels").addDocument(from: addedHotel)
以上代码应获取旅行的文档 ID,您可以手动附加或构建应传递给酒店文档的数据。
您可以找到更多相关信息here。
让我们从澄清这一点开始
not using nested data structure
Firebase 中的一切都是嵌套的! - 这就是它的工作方式。这是关于深度嵌套数据的参考,因为它很难获得 to/query 等,因此对数据进行非规范化或扁平化是一种常用的做法。
有多种方法可以获取您想要的数据,但让我 re-state 这个问题
I have trips and each trip has a number of associated hotels. My goal
is to read the hotels for each trip to calculate a total cost for
those hotels.
TL;DR 跳到底部:一个快速的事情部分
这是一种结构
trip_0
trip_name: "Napa trip"
hotels:
hotel_0: true
hotel_1: true
hotel_2: true
使用该结构,阅读 trip_0 将提供关联的酒店。然后您遍历该数组(映射)并读取 hotel_0 并获取它的成本,然后 hotel_1 并获取它的成本。把成本加起来,你就完成了。无需查询。
第二个选项是反向方法,使用链接酒店和旅行的单独集合 - 这需要查询以获取与每次旅行关联的酒店
hotels_trips
hotel_0
trip_0: true
trip_1: true
trip_2: true
hotel_1
trip_1: true
根据以上内容,运行 对 hotels_trips 集合中的酒店的查询 trip_1 为真。获得酒店列表后,您可以阅读每个酒店以了解其成本并将其相加。
另一种解决方案是使用 arrayContains 的结构和查询:
hotels
hotel_0
hotel_name: "Hotel California"
cost: 500
trip_array
0: trip_0
1: trip_1
然后是查询酒店集合中包含 trip_0
的所有酒店的代码
func queryHotels() {
let hotelCollection = self.db.collection("hotels")
hotelCollection.whereField("trip_array", arrayContains: "trip_0").getDocuments { querySnapshot, error in
if let err = error {
print(err.localizedDescription)
return
}
guard let docs = querySnapshot?.documents else { return }
for doc in docs {
let name = doc.get("name") as! String
print(name)
}
}
}
一件小事:数组通常很难在像 Firebase 这样的 NoSQL 数据库中使用,所以我通常会避免使用它们。您可能要考虑使用 Map 而不是数组,然后在路径 trip_map/trip_0
上查询以查看它是否为真。酒店结构将包括此而不是 trip_array
trip_map
trip_0: true
trip_1: true
并且查询将测试路径以查看其值是否为真
hotelCollection.whereField("trip_map.trip_0", isEqualTo: true).getDocuments { querySnapshot, error in
阅读文档后,他们建议不要使用嵌套数据结构。我认为这是处理我的数据的最佳方式,但我不确定如何将 tripId 添加到酒店集合中。
我的另一个选择是让用户为每个酒店条目输入“BOL”...我对该方法的问题是如何查询日期以查看与“行程”匹配的所有酒店?
编辑:::::::: 我想要完成的是,当用户选择一次旅行时,它会运行一个查询并显示与该旅行相关的酒店的所有夜晚总数。
users:
- gCFiwSLwBeg87N6GfeofFxIAZyi2
- UID: gCFiwSLwBeg87N6GfeofFxIAZyi2
- firstName: "James"
- email: "a@email.com"
trips:
- "random document id"
- bol: "1234567"
- startDate: "1/3/2022"
- destination: "Sacramento, CA"
- userID: "Users UID"
- foodTotal: "100"
- hotelTotal: "240"
- "random document id"
- bol: "256976"
- startDate: "2/5/2022"
- destination: "Orlando, FL"
- userID: "Users UID"
- foodTotal: "150"
- hotelTotal: "400"
hotels:
- "random document id"
- tripId: ?
- date: "1/4/2022"
- destination: "Sacramento, CA"
- userID: "Users UID"
- name: "Hotel Inn"
- cost: "120"
- "random document id"
- tripId: ?
- date: "1/5/2022"
- destination: "Sacramento, CA"
- userID: "Users UID"
- name: "Hotel Inn"
- cost: "120"
这是我目前用来将酒店添加到 firebase 的函数。
class FirebaseHotelRepository: HotelRepositoryProtocol {
private let db = Firestore.firestore()
func addHotel(hotel: Hotel, completion: @escaping (Result<Hotel?, Error>) -> Void) {
do {
var addedHotel = hotel
addedHotel.userId = Auth.auth().currentUser?.uid
let _ = try db.collection("hotels").addDocument(from: addedHotel)
} catch {
fatalError("Unable to encode trip: \(error.localizedDescription)")
}
}
}
class AddHotelViewModel: ObservableObject {
private let repo: HotelRepositoryProtocol
var name: String = ""
var location: String = ""
var date = Date()
var cost: String = ""
@Published var saved: Bool = false
init(repo: HotelRepositoryProtocol) {
self.repo = repo
}
func addHotel() {
let hotel = Hotel(bol: bol,
name: name,
location: location,
date: date,
cost: cost,
color: UIColor(color).hexStringFromColor())
repo.addHotel(hotel: hotel) { result in
switch result {
case .success(let savedHotel):
DispatchQueue.main.async {
self.saved = savedHotel == nil ? false : true
}
case .failure(let error):
print(error.localizedDescription)
}
}
}
}
从这个documentation:
In some cases, it can be useful to create a document reference with an auto-generated ID, then use the reference later. For this use case, you can call doc():
这里有一个示例代码,您可以参考:
let trips = db.collection("trips").addDocument(data: [
// trips' data
])
// This will append tripId to the `addedHotel`
addedHotel["tripId"] = trips.documentID
let hotels = db.collection("hotels").addDocument(from: addedHotel)
以上代码应获取旅行的文档 ID,您可以手动附加或构建应传递给酒店文档的数据。
您可以找到更多相关信息here。
让我们从澄清这一点开始
not using nested data structure
Firebase 中的一切都是嵌套的! - 这就是它的工作方式。这是关于深度嵌套数据的参考,因为它很难获得 to/query 等,因此对数据进行非规范化或扁平化是一种常用的做法。
有多种方法可以获取您想要的数据,但让我 re-state 这个问题
I have trips and each trip has a number of associated hotels. My goal is to read the hotels for each trip to calculate a total cost for those hotels.
TL;DR 跳到底部:一个快速的事情部分
这是一种结构
trip_0
trip_name: "Napa trip"
hotels:
hotel_0: true
hotel_1: true
hotel_2: true
使用该结构,阅读 trip_0 将提供关联的酒店。然后您遍历该数组(映射)并读取 hotel_0 并获取它的成本,然后 hotel_1 并获取它的成本。把成本加起来,你就完成了。无需查询。
第二个选项是反向方法,使用链接酒店和旅行的单独集合 - 这需要查询以获取与每次旅行关联的酒店
hotels_trips
hotel_0
trip_0: true
trip_1: true
trip_2: true
hotel_1
trip_1: true
根据以上内容,运行 对 hotels_trips 集合中的酒店的查询 trip_1 为真。获得酒店列表后,您可以阅读每个酒店以了解其成本并将其相加。
另一种解决方案是使用 arrayContains 的结构和查询:
hotels
hotel_0
hotel_name: "Hotel California"
cost: 500
trip_array
0: trip_0
1: trip_1
然后是查询酒店集合中包含 trip_0
的所有酒店的代码func queryHotels() {
let hotelCollection = self.db.collection("hotels")
hotelCollection.whereField("trip_array", arrayContains: "trip_0").getDocuments { querySnapshot, error in
if let err = error {
print(err.localizedDescription)
return
}
guard let docs = querySnapshot?.documents else { return }
for doc in docs {
let name = doc.get("name") as! String
print(name)
}
}
}
一件小事:数组通常很难在像 Firebase 这样的 NoSQL 数据库中使用,所以我通常会避免使用它们。您可能要考虑使用 Map 而不是数组,然后在路径 trip_map/trip_0
上查询以查看它是否为真。酒店结构将包括此而不是 trip_array
trip_map
trip_0: true
trip_1: true
并且查询将测试路径以查看其值是否为真
hotelCollection.whereField("trip_map.trip_0", isEqualTo: true).getDocuments { querySnapshot, error in