8
votes

Ajouter l'ID de document d'un document à son propre document Firestore - Swift 4

Comment puis-je ajouter l'ID de document d'un document que je viens d'ajouter à ma base de données Firestore, audit document?

Je veux faire cela pour que lorsqu'un utilisateur récupère un objet "ride" et choisisse de réserver il, je peux savoir quel trajet spécifique ils ont réservé.

Le problème auquel je suis confronté est que vous ne pouvez pas obtenir l'ID du document avant sa création, donc la seule façon de l'ajouter à ledit document serait de créer un document, de lire son identifiant, puis de modifier le document pour l'ajouter à l'identifiant. À grande échelle, cela créerait deux fois plus d'appels au serveur que vous le souhaitez.

Existe-t-il un moyen standard de le faire? Ou une solution simple pour savoir quel "trajet" l'utilisateur a réservé et le modifier en conséquence dans la base de données?

struct Ride {
    var availableSeats: Int
    var carType: String
    var dateCreated: Timestamp
    var ID: String // How do I implement this?
}


func createRide(ride: Ride, completion: @escaping(_ rideID: String?, _ error: Error?) -> Void) {
    // Firebase setup
    settings.areTimestampsInSnapshotsEnabled = true
    db.settings = settings

    // Add a new document with a generated ID
    var ref: DocumentReference? = nil
    ref = db.collection("rides").addDocument(data: [
        "availableSeats": ride.availableSeats,
        "carType": ride.carType,
        "dateCreated": ride.dateCreated,
        "ID": ride.ID,
    ]) { err in
        if let err = err {
            print("Error adding ride: \(err)")
            completion(nil, err)
        } else {
            print("Ride added with ID: \(ref!.documentID)")
            completion(ref?.documentID, nil)
            // I'd currently have to use this `ref?.documentID` and edit this document immediately after creating. 2 calls to the database.
        }
    }
}


0 commentaires

3 Réponses :


3
votes

Je pense que si vous utilisez le générateur d'ID intégré de Swift, appelé UUID , fourni par le framework Foundation , cela vous permettra de faire ce que vous voulez faire. Veuillez consulter le code ci-dessous pour mes modifications recommandées. Aussi en procédant de cette façon, lorsque vous initialisez votre structure "Ride" pour la première fois, vous pouvez générer sa variable ID alors, au lieu de le faire à l'intérieur de la fonction. C'est ainsi que je génère des identifiants uniques dans toutes mes applications et cela fonctionne parfaitement! J'espère que cela vous aidera!

struct Ride {
    var availableSeats: Int
    var carType: String
    var dateCreated: Timestamp
    var ID: String
}


func createRide(ride: Ride, completion: @escaping(_ rideID: String, _ error: Error?) -> Void) {
    // Firebase setup
    settings.areTimestampsInSnapshotsEnabled = true
    db.settings = settings

    // Add a new document with a generated ID
    var ref: DocumentReference? = nil
    let newDocumentID = UUID().uuidString
    ref = db.collection("rides").document(newDocumentID).setData([
        "availableSeats": ride.availableSeats,
        "carType": ride.carType,
        "dateCreated": ride.dateCreated,
        "ID": newDocumentID,
    ], merge: true) { err in
        if let err = err {
            print("Error adding ride: \(err)")
            completion(nil, err)
        } else {
            print("Ride added with ID: \(newDocumentID)")
            completion(newDocumentID, nil)
        }
    }
}


2 commentaires

Solution parfaite! Cette fonction UUID créera-t-elle un jour le même identifiant deux fois?


Pas de soucis! Non, tant que vous réutilisez "let newDocumentID = UUID (). UuidString" dans la même fonction pour autre chose, par exemple pour une nouvelle référence de document, tout devrait être parfait! 👌



11
votes

Bien qu'il y ait une réponse parfaitement fine, FireStore a la fonctionnalité dont vous avez besoin intégrée, et il ne nécessite pas deux appels à la base de données. En fait, il ne nécessite aucun appel à la base de données.

Voici un exemple

    var aRide = RideClass(seats: 3, car: "Lincoln", createdDate: "20190122")

    var ref: DocumentReference? = nil
    ref = db.collection("rides").addDocument(data: aRide.getRideDict() ) { err in
        if let err = err {
            print("Error adding document: \(err)")
        } else {
            aRide.ID = ref!.documentID
            print(aRide.ID) //now you can work with the ride and know it's ID
        }
    }

Voir la documentation Ajoutez un document pour plus d'informations.

Dans certains cas, il peut être utile de créer une référence de document avec un ID généré automatiquement, puis utilisez la référence plus tard. Pour ce cas d'utilisation, vous pouvez appeler doc ():

Vous pouvez envisager une approche légèrement différente. Vous pouvez également obtenir l'ID du document dans la fermeture après l'écriture. Alors, nous allons vous donner un Ride (classe) sympa

class RideClass {
    var availableSeats: Int
    var carType: String
    var dateCreated: String
    var ID: String

    init(seats: Int, car: String, createdDate: String) {
        self.availableSeats = seats
        self.carType = car
        self.dateCreated = createdDate
        self.ID = ""
    }

    func getRideDict() -> [String: Any] {
        let dict:[String: Any] = [
            "availableSeats": self.availableSeats,
            "carType": self.carType,
            "dateCreated": self.dateCreated
        ]
        return dict
    }
}

puis du code pour créer un tour, l'écrire et tirer parti de son ID de document créé automatiquement

    let testRef = self.db.collection("test_node")
    let someData = [
        "child_key": "child_value"
    ]

    let aDoc = testRef.document() //this creates a document with a documentID
    print(aDoc.documentID) //prints the documentID, no database interaction
    //you could add the documentID to an object etc at this point
    aDoc.setData(someData) //stores the data at that documentID


2 commentaires

Cela ressemble à une double lecture et écriture. Free Tire serait lourdement pilonné par cet appel. Y a-t-il une solution de contournement ?


@EngineSense Je ne sais pas ce que vous voulez dire. Dans la première partie de ma réponse, il n'y a pas du tout de lecture OU d'écriture. Dans le deuxième exemple, il s'agit d'une seule écriture. Qu'est-ce que Pneu gratuit et pourquoi serait-il lourdement martelé puisqu'il s'agit d'une seule écriture?



1
votes

Voici ma solution qui fonctionne comme un charme

    let opportunityCollection = db.collection("opportunities")
    let opportunityDocument = opportunityCollection.document()
    let id = opportunityDocument.documentID

    let data: [String: Any] = ["id": id,
                               "name": "Kelvin"]

    opportunityDocument.setData(data) { (error) in
        if let error = error {
            completion(.failure(error))
        } else {
            completion(.success(()))
        }
    }


0 commentaires