0

I'm working on an Ionic project in which I would like to upload photos and add them to a specific node in Firebase storage. For now what I do is upload photos in STORAGE.
What I would like to do, instead, is to upload this photos not in storage, but reference them in a node, like this:

enter image description here

This I've done manually by uploading the photo on imgur and copying the link there, but I need an automatic procedure to let the user upload photos to a specific city.
Let's say the user is in a city, takes a photo and uploads it on Firebase. By uploading it on STORAGE, it is possible to get the cityname where he is and add a new photo by calling it, for example, "UserName_CityName_Photo". But since a user can upload more than one photo of the same city, and in different times, how can I easily upload a new one without overwriting the photo that is already in storage?
For this reason I was wondering if there's a way to upload photo not on storage, but directly on database, for example by generating a referring URL, so that every new photo is simply appended under the corresponding node.

Usr
  • 2,628
  • 10
  • 51
  • 91
  • you can use geolocation to tag photos when the user is taking the photo and store them in firebase – Abdul Karim Nov 21 '17 at 12:31
  • @AbdulKarim but what if the user takes two photo of the same place? – Usr Nov 21 '17 at 13:12
  • both phots will have the location metadata added – Abdul Karim Nov 21 '17 at 13:14
  • so u mean also a timestamp? – Usr Nov 21 '17 at 13:16
  • No, every photo user will take be tagged with lat. and long. which you can use to find a place, name or whatever you want. – Abdul Karim Nov 21 '17 at 13:22
  • Ok, so the question remains: if a user takes two photos, one after the other, the lat and long info will remain the same. So the photo will be overwritten – Usr Nov 21 '17 at 13:24
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/159487/discussion-between-abdul-karim-and-user999). – Abdul Karim Nov 21 '17 at 13:24
  • 1
    If you use the autoId it won't matter if the location is the same. Upload the photos to city then autoId or even just autoId will work without there being a duplicate. Thus none of your files will get overwritten. – DoesData Nov 21 '17 at 14:46

1 Answers1

0

So you can upload an image to Firebase database, but it has to be in binary or something weird and it's generally not accepted practice. To make these urls unique in storage you can upload them under CityName -> autoIdKey which will be unique. This also means all the images of a city will be under it's name in storage which might be handy later.

You can get the current users city using this code

import Foundation
import MapKit

typealias JSONDictionary = [String:Any]

class LocationServices {

    let shared = LocationServices()
    let locManager = CLLocationManager()
    var currentLocation: CLLocation!

    let authStatus = CLLocationManager.authorizationStatus()
    let inUse = CLAuthorizationStatus.authorizedWhenInUse
    let always = CLAuthorizationStatus.authorizedAlways

    func getAdress(completion: @escaping (_ address: JSONDictionary?, _ error: Error?) -> ()) {

        self.locManager.requestWhenInUseAuthorization()

        if self.authStatus == inUse || self.authStatus == always {

            self.currentLocation = locManager.location

            let geoCoder = CLGeocoder()

            geoCoder.reverseGeocodeLocation(self.currentLocation) { placemarks, error in

                if let e = error {

                    completion(nil, e)

                } else {

                    let placeArray = placemarks as? [CLPlacemark]

                    var placeMark: CLPlacemark!

                    placeMark = placeArray?[0]

                    guard let address = placeMark.addressDictionary as? JSONDictionary else {
                        return
                    }

                    completion(address, nil)

                }

            }

        }

    }

}

Function to get the city name:

    func getCityName() -> String {
        LocationServices.shared.getAdress { address, error in
            if let a = address, let city = a["City"] as? String {
                   return city
            }
            else {
                return "NO_CITY_NAME"
            }
        }
    }

Upload and get the storage URL:

@IBAction func postPressed(_ sender: Any) {

        // get the cityname
        let city = getCityName()
        let uid = Auth.auth().currentUser!.uid
        let ref = Database.database().reference()
        let storage = Storage.storage().reference(forURL: "gs://YourUrlHere")
        let key = ref.child("pois").childByAutoId().key // unique key

        let imageRef = storage.child("pois").child(city).child("\(key).jpg")

        let data = UIImageJPEGRepresentation(photo, 0.6) 

        let uploadTask = imageRef.putData(data!, metadata: nil) { (metadata, error) in
            if error != nil {
                // do something
                return
            }

            imageRef.downloadURL(completion: {(url, error) in
                // upload of image worked now get the url to upload to your database

                if let url = url, let author = Auth.auth().currentUser?.displayName {
                    let feed = ["city": ,
                                "pathToImage": url.absoluteString, // here is your storage url to upload to Firebase DB
                                : key] as [String: Any]

                    let postFeed = ["\(key)" : feed]

                    ref.child("pois").updateChildValues(postFeed, withCompletionBlock: { (error, success) in
                        if error != nil {
                            // do something
                            return
                        }
                        else {
                            // data successfully uploaded
                        }            
                    })
                }
            })
        }
        uploadTask.resume()

        uploadTask.observe(.success) { (snapshot) in
            // do something when upload is finished
            return
        }
        uploadTask.observe(.failure) { (snapshot) in
            // do something on failure
            return
        }
}
DoesData
  • 6,594
  • 3
  • 39
  • 62
  • Hi, thanks for the reply. I have just one question: when you talk about the URL to add to the child, you are referring to the imgur URL, right? – Usr Nov 21 '17 at 13:18
  • 1
    Yes the imageURL. You actually can't use that to upload it to storage because you won't have it until the upload is finished so you'll have to do city -> autoId for the storage path like I did. Apologies. – DoesData Nov 21 '17 at 13:25