将文档ID添加到其自身的Firestore文档 - Swift 4

13
我如何在刚添加到我的firestore数据库的文档中添加文档ID,以便当用户检索“ride”对象并选择预订时,我可以知道他们预订了哪个特定的ride?
问题在于在创建文档之前无法获取文档ID,因此将其添加到所述文档的唯一方法是创建文档,读取其ID,然后编辑文档以添加ID。 在规模上,这将创建两倍于期望数量的服务器调用。是否有标准方法来解决这个问题?或者是否有简单的解决方案来知道用户预订了哪个“ride”并相应地在数据库中进行编辑?
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.
        }
    }
}
3个回答

15

虽然已经有一个很好的答案了,但是FireStore已经内置了你需要的功能,并且它不需要对数据库进行两次调用。事实上,它不需要任何对数据库的调用。

这里有一个例子:

    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

查看文档添加文档以获取更多信息。

在某些情况下,创建一个具有自动生成的 ID 的文档引用,然后稍后使用该引用可能很有用。对于这种用例,您可以调用doc():

您可能希望考虑略微不同的方法。您还可以在写入后的闭包中获取文档ID。因此,让我们为您提供一个酷炫的Ride(类)。

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
    }
}

然后编写一些代码来创建一个 ride,将其写出并利用其自动生成的 documentID。

    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
        }
    }

似乎是双重读写。这个调用会严重影响免费层的性能。有什么解决方法吗? - EngineSense
@EngineSense 不确定你的意思。在我的回答的第一部分中根本没有读取或写入。在第二个例子中,只有一个写入操作。什么是“Free tire”,为什么它会被大量使用,因为它只有一个写入操作? - Jay

4

我相信如果你使用Swift内置的ID生成器,称为UUID,由Foundation框架提供,这将让你做想做的事情。请参见下面的代码,以了解我的建议更改。此外,通过这种方式,在首次初始化“Ride”结构时,您可以生成其ID变量,而不是在函数内部执行此操作。这是我在应用程序中生成唯一ID的方法,它完美地工作!希望这能帮到你!

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)
        }
    }
}

完美的解决方案!但是这个 UUID 函数会不会创建两次相同的 ID 呢? - yambo
2
没问题!只要你在同一个函数中再次使用“let newDocumentID = UUID().uuidString”来创建新的文档引用,那么就完全没问题! - WH48

2
这是我的解决方案,它的效果非常好。
    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(()))
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接