0

players array in firestore

struct Game: Codable {
    
    let id: String
    
    var table = Table()
    
    var players = [Player]()
    
    var player1ID = ""
    var player2ID = ""
    
    var currentPlayerSetCountShouldAnimate = false
    var opponentSetCountShouldAnimate = false
    
    init(currentPlayer: Player) {
        id = UUID().uuidString
        players.append(currentPlayer)
        players[0].playerNumber = 0
        player1ID = currentPlayer.id
    }
}

struct Player: Codable, Equatable {
    var id = UUID().uuidString
    
    var playerNumber = 0
    
    var selectedCards: [Card]
    var collectedSets: [Card]
    var selectedCardsIndexes: [Int]
    
}

I'm storing the Game object in a Firestore database. Rather than updating the entire game when a Card object is added to the selectedCards array, I want to update only the selectedCards array for the currentPlayer.

func updatePlayerSelectedCards(player: Player) {
    do {
        let selectedCards = try JSONEncoder().encode(player.selectedCards)
        let gameRef = Firestore.firestore().collection("Game").document(game.id)
        let playerRef = gameRef.collection("players")

        playerRef.document("\(player.playerNumber)").updateData(["selectedCards": selectedCards]) { (error) in
            if let error = error {
                print("Error updating selectedCards field: \(error)")
            } else {
                print("Successfully updated selectedCards field")
            }
        }
    } catch {
        print(error.localizedDescription)
    }
}

I've written a number of variations on this function, but when I try to access the playerNumber index of the players array, it gives me this error:

[FirebaseFirestore][I-FST000001] WriteStream (7f9b27810c08) Stream error: 'Not found: No document to update: projects/setgamebc/databases/(default)/documents/Game/FC600D8C-85DC-4465-8648-31FFA90086EB/players/0'

In the attached image, it's clear that the index (0 in this case) exists in the player array. Is it not a document? Do I need to use FieldValue.arrayUnion for this? This is my first "large" project, and I feel like accomplishing this shouldn't be that hard, so I think I may be missing something simple. Any help and clarification would be greatly appreciated.

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
brad8989
  • 1
  • 1
  • There is no operator to update an item in an array field in Firestore; the only operators are to add a unique item, remove specific items, or to set the entire field. So you'll have to: 1) read the array, 2) update it in your application code, 3) write the entire array back to the database. – Frank van Puffelen Jan 03 '23 at 20:25

1 Answers1

0

The problem starts here:

let playerRef = gameRef.collection("players")
playerRef.document("\(player.playerNumber)")...

This code tries to update a $player.playerNumber document in a players collection. But your screenshot shows a players field in an otherwise named document. So there is no document called players, which explains the error message.

There is no way operator to update an item in an array field in Firestore; the only operators are to add a unique item, remove specific items, or to set the entire field.

So if the array_union operator is not good enough for your use-case, you'll have to: 1) read the array, 2) update it in your application code, 3) write the entire array back to the database.

Also see: Firestore Update single item in array of objects

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807