11

first of all I've seen answers : here but for me coming from android and angular is just mind blowing to have to write so much code (where in android and angular it takes one line) plus answers are not the latest one so wonder if there is any better way nowadays

for clarification here is my example:

struct User{
  let fistName:String
  let lastName:String
}

and I retrieving data with :

Firestoer.firestore().collection("users").document('someId').getDocument{
   (snapshot,error) in 
}

The question is how to assign snapshot values to User object values ith one line of code - soething like user = snapshot -ish .

pb4now
  • 1,305
  • 4
  • 18
  • 45
  • The answer is pretty well laid out in the documentation. Check out [Get data with Cloud Firestore](https://firebase.google.com/docs/firestore/query-data/get-data) in the Custom Objects section. There's an example of reading a Cities node and returning each city as a City object. Very similar to what your are doing with your User object. – Jay Jun 06 '18 at 17:41
  • @Jay yeap I've seen it ,I can not make it work, it says: "return City(dictionary: data)" - my object is simple "stuct" and I could not make "(dictionary: data)" -call. So I went back in firestore documetation to see how they set up a custom object but there (under addData/custom object) it says: "/This isn't supported in Swift. Use a value type instead." when they say "value" I understand it as I should call "document.get("firstName") as String" for every single variable in the Object- maybe I understand that incorrecly..? – pb4now Jun 06 '18 at 18:35
  • I think you overlooked *In Add Data, you defined a City class that you used to define each city. You can turn your document back into a City object:*. The City(dictionary: is an initializer for the city class that takes the key: value pairs in the passed dictionary and assigns them to the City properties. You could do the same thing with User or simply *let aUser = User(firstName: fName, lastName: lName)* where fName and lName are values within the returned snapshot. – Jay Jun 06 '18 at 18:59
  • but to pass fName and lName I need to 'extract' thoese values from snapshot for every single variable anyway with something like fName=snapshot.get("firstName"). right? -or am I missunderstanding U and getting dumber by the minute at this moment?:S – pb4now Jun 06 '18 at 19:34
  • You're on the right path; if you are getting a specific document, access properties something like this *document.data()!["fName"]*. Keep in mind that if you are returning multiple documents in your snapshot, you'll need to iterate over them to work with each one. – Jay Jun 06 '18 at 20:26
  • yea -that part I understand I was looking for assigning the whole object dierecly to an Object with one line instead of extracting data from an snapshot something like "snapshot.toObject(User) "(that is in angular and android):S – pb4now Jun 07 '18 at 06:47
  • You answered your own question in your comment! Just add an initializer to your User object and pass it the snapshot to initialize it! i.e. if you want to use a struct something like *let user = User()* and then *user.loadData(fromSnap: snapshot)* or use an extension and make it a class and use a convenience initializer. – Jay Jun 07 '18 at 13:50
  • hehe, but still I have to add extra code to my User initializer where I extract data from snapshot- there is no need to do that on the other platforms (angular , android -in that case) it direcly matches names of User variables with the "keys" of snapshot -no need of any kind of iterration, but at this point I'm just guessing that there is no sucha way in swift – pb4now Jun 07 '18 at 14:13
  • 1
    That's not really how the process works, it's not iterating; it's passing the snapshot to the class to have the variables populated with the data from the snapshot. You would only need to iterate (think: loop) if you are instantiating multiple user objects via a .value observe and that process would need to happen on any platform. The User class/struct still needs to have properties defined and you would need to know the structure of the firebase node being read. It could be a key: value pair of a single string, or a key: snapshot pair or a number of other structures. – Jay Jun 07 '18 at 14:52

2 Answers2

0

Reading through your comments, it is difficult to understand where exactly you are having a problem. I'm going to assume it's because you did not know how to write the other initializer due to your first comment:

`my object is simple "stuct" and I could not make "(dictionary: data)" -call.`

Here's the initializer you could use:

extension User {
    init?(dictionary: [String: Any]){
        guard let firstName = dictionary["firstName"] as? String else { return nil }
        guard let lastName = dictionary["lastName"] as? String else { return nil }
    }
        self.init(firstName: firstName, lastName: lastName)
}
AgRizzo
  • 5,261
  • 1
  • 13
  • 28
  • yea,sorry -it seams like I was unclear with my question: what I ment is that I was looking for one line code that matches variables of any Object (User in this case) with data in a snapshot with no need of putting extra code to extract data from snapshot-like in what U wrote, U hade to put two lines of code to get values for two variables - so now If U had 20 classes with 10 variables that would be 200 code lines -where in angular and android preaty much I do something like "let user = snapshot as User" and that's it – pb4now Jun 07 '18 at 14:22
  • 1
    @pb4now - There is no magic one line of code. You will need to correlate the format of the data returned in the Snapshot to the required properties of your struct / class. Using the *Codable* protocol can help reduce the amount of code you need to write, but you still will need to write some code. – AgRizzo Jun 07 '18 at 16:30
-1

I finally found that simply swift firestore sdk still missing that function but it seams like it is in works and you can find discussion about that in here

...We've had something like this on our radar for a bit. Essentially we want to provide an equivalent to the Android DocumentSnapshot.toObject.

, hopefully it's done soon...

pb4now
  • 1,305
  • 4
  • 18
  • 45
  • You still need to make your class / struct conform to the Codable protocol - which means you will still have to write code. BTW: You don't need this future feature to get this functionality now. Go watch [this video on Swift CRUD with Firestore](https://www.youtube.com/watch?v=24ef-Zwz2v8) to understand how to set up the functionality you want. – AgRizzo Jun 14 '18 at 09:52