简体   繁体   English

如何在 SwiftUI 的 Firestore 中添加动态子集合数据?

[英]How Do I Add Dynamic Sub Collection Data In Firestore In SwiftUI?

I'm new to swift and firebase and am trying lots of things out.我是 swift 和 firebase 的新手,正在尝试很多事情。 I have created a collection of "characters" in firebase which are displayed in the app.我在应用程序中显示的 firebase 中创建了一组“字符”。 The aim is there are "characters" you unlock by earning points.目的是通过赚取积分来解锁“角色”。 Points are earned by walking (getting steps using HealthKit)通过步行获得积分(使用 HealthKit 获取步数)

When a user taps on a character and then taps "unlock" its added to a struct called UnlockingCharacters.当用户点击一个字符然后点击“解锁”时,它被添加到一个名为 UnlockingCharacters 的结构中。

UnlockingCharacters are shown in the users profile. UnlockingCharacters 显示在用户配置文件中。

I need to make the UnlockingCharacters struct part of the users document on Firebase (maybe as a subcollection?)我需要在 Firebase 上制作用户文档的 UnlockingCharacters 结构的一部分(也许作为子集合?)

I want to limit the number of characters in UnlockingCharacters to 2. Characters are unlocked by taking steps which are turned into points.我想将 UnlockingCharacters 中的字符数限制为 2。通过采取变成点的步骤来解锁字符。 When points are uploaded to firebase, the character receives these points and adds it to its total (a characters points total is the sum of all users that are unlocking the characters points).当点数上传到 Firebase 时,角色会收到这些点数并将其添加到其总数中(角色点数是所有解锁角色点数的用户的总和)。

Here is the Character Model:下面是人物模型:

struct Character: Identifiable, Decodable {
    
@DocumentID var id: String?
    var character_name: String
    var character_type: String
    var character_image: String
    var character_details: String
    var character_usersUnlocking: Int
    var character_totalPoints: Int
    var user: UserModel?
    var didUnlock: Bool? = false
      
    // To identify whether it is being unlocked...
    var isUnlocking: Bool = false
    
}

Here is the UnlockingCharacters model:这是 UnlockingCharacters 模型:

struct UnlockingCharacters: Identifiable {
    
    var id = UUID().uuidString
    var character: Character
}

SharedDataModel:共享数据模型:

class SharedDataModel: ObservableObject {
   
    // Unlocking Characters...
    @Published var unlockingCharacters: [Character] = [] 
}

My Functions:我的功能:

 func isUnlocked() -> Bool {
        
        return sharedData.unlockingCharacters.contains { characterData in
            return self.characterData.id == characterData.id
        }
    }

    func addToUnlocking() {

        if let index = sharedData.unlockingCharacters.firstIndex(where: {

            characterData in
            return self.characterData.id == characterData.id
        }){
            // Remove from unlocking...
            sharedData.unlockingCharacters.remove(at: index)
        }
        else {
            // Add to unlocking...
            sharedData.unlockingCharacters.append(characterData)
        }
    }

I know that something needs to be added to my UserModel too however I am getting an error:我知道我的 UserModel 也需要添加一些东西,但是我收到一个错误:

struct UserModel: Identifiable, Decodable {
    var username : String
    var pic : String
    var bio: String
    var uid : String
    var id: String { uid }  

//I am getting error for the following variable:
(Value type 'UserModel' cannot have a stored property that recursively contains it)

    var activeUnlockingCharacters: UnlockingCharacters
}

To sum up I need UnlockingCharacters to be added to the users document on Firebase.总而言之,我需要将 UnlockingCharacters 添加到 Firebase 上的用户文档中。

I'm getting an error processing a custom object.我在处理自定义对象时遇到错误。 Here is my code:这是我的代码:

let ref = Firestore.firestore()

func fetchUser(uid: String,completion: @escaping (UserModel) -> ()){
    
    let db = Firestore.firestore()
    
    ref.collection("Users").document(uid).getDocument { (doc, err) in
        guard let user = doc else{return}
        
        let username = user.data()?["username"] as? String ?? "No Username"
        let pic = user.data()?["imageurl"] as? String ?? "No image URL"
        let bio = user.data()?["bio"] as? String ?? "No bio"
        let uid = user.data()?["uid"] as? String ?? ""
 
        do {
            try db.collection("Users").document("\(uid)").setData(from: UnlockingCharacters)
        } catch let error {
            print("Error writing object to Firestore: \(error)")
        }
        
        DispatchQueue.main.async {
            completion(UserModel(username: username, pic: pic, bio: bio, uid: uid, activeUnlockingCharacters: UnlockingCharacters))
        }
    }
}

The error in the do is: "Type 'UnlockingCharacters.Type' cannot conform to 'Encodable'"做的错误是:“类型'UnlockingCharacters.Type'不能符合'Encodable'”

The error in the DispatchQueue is: "Cannot convert value of type 'UnlockingCharacters.Type' to expected argument type '[UnlockingCharacters]'" DispatchQueue 中的错误是:“无法将 'UnlockingCharacters.Type' 类型的值转换为预期的参数类型 '[UnlockingCharacters]'”

Get rid of var user: UserModel?摆脱var user: UserModel? in CharacterCharacter

Then you can find the characters under activeUnlockingCharacters然后就可以找到activeUnlockingCharacters下的字符了

or something like或类似的东西

UserModel/{uid}/UnlockingCharacters

You can make你(们)能做到

var activeUnlockingCharacters: UnlockingCharacters

An Array数组

var activeUnlockingCharacters: [UnlockingCharacters]

Then use validation or rules to limit the count to 2然后使用验证或规则将计数限制为 2

Firebase has a whole section on how to process custom objects. Firebase 有一整节介绍如何处理自定义对象。

https://firebase.google.com/docs/firestore/manage-data/add-data#custom_objects https://firebase.google.com/docs/firestore/manage-data/add-data#custom_objects

if you have all your structs conform to Codable如果你的所有结构都符合 Codable

do {
    try db.collection("UserModel").document("\(uid)").setData(from: userModelObject)
} catch let error {
    print("Error writing object to Firestore: \(error)")
}

And to read并阅读

https://firebase.google.com/docs/firestore/query-data/get-data https://firebase.google.com/docs/firestore/query-data/get-data

let docRef = db.collection("UserModel").document("\(uid)")

docRef.getDocument(as: UserModel.self) { result in
    // The Result type encapsulates deserialization errors or
    // successful deserialization, and can be handled as follows:
    //
    //      Result
    //        /\
    //   Error  UserModel
    switch result {
    case .success(let userModel):
        // A `Model` value was successfully initialized from the DocumentSnapshot.
        print("Model: \(userModel)")
    case .failure(let error):
        // A `Model` value could not be initialized from the DocumentSnapshot.
        print("Error decoding object: \(error)")
    }
}

You can also user the new @FirestoreQuery and use rules to limit the object that is visible您还可以使用新的@FirestoreQuery并使用规则来限制可见的对象

https://firebase.google.com/docs/reference/swift/firebasefirestoreswift/api/reference/Structs/FirestoreQuery https://firebase.google.com/docs/reference/swift/firebasefirestoreswift/api/reference/Structs/FirestoreQuery

Set in the rules that the user is the only one that can read its own UserModel based on auth.在规则中设置用户是唯一可以基于auth读取自己的UserModel的用户。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM