Use variable to get database info

Hi all,

The idea is to use a code inputed from scanning a bar code to get the information from the database. I have the bar scanning bit done, my problem is using the variable to get the data from the DB.

Specs:
Xcode (swift)
user interface = SwiftUI
Database = Firebase (Firestore)

the set up between Xcode and firebase is working and I am able to read data. However I want to use a variable as the pathway to the database instead of a constant.
How can I do this?

All of my code → codetofix - Google Drive

I am not very experienced to Xcode and swift but in all I believe this should just be a simple fix where I replace the bit of code

return products(id: d.documentID,
                                            name: d["name"] as? String ?? "",
                                            scannedCode2: d["scannedCode2"] as? String ?? "",
                                            notes: d["notes"] as? String ?? "")

with my var → scannedCode as the file path to the data

nothing is working for me though, and there are lots of problems around using the var I get ‘scannedCode’ form scanning the bar code in different places.

Any help is greatly appreciated thanks! :pray:

Some Screenshots

It wouldn’t let me post more then one picture at a time.

G’Day @Toby,

Welcome to the community.

Can you post your code as text rather than posting a photo?

Copy the code from Xcode and paste in a reply. Format each code block as per the following and that will make it a lot easier for us to help you.

To format the code nicely, place 3 back-ticks ``` on the line above your code and 3 back-ticks ``` on the line below your code. Like this:

```
Code goes here
```

The 3 back-ticks must be the ONLY characters on the line. The back-tick character is located on the same keyboard key as the tilde character ~ (which is located below the Esc key - QWERTY keyboard).

Alternatively after you paste in your code, select that code block and click the </> button on the toolbar. This does the same thing as manually typing the 3 back ticks on the line above and below your code.

This also makes it easier for anyone assisting as they can copy the code and carry out some testing.

okay, all I’m trying to figure out is how to use a variable to get data from the database

//importing dependencies
import SwiftUI
import CodeScanner
import Firebase
import Foundation

struct ContentView: View {
    @State var isPresentingScanner = false
    @State public var scannedCode: String = "Scan a bar code to get started."
    // tring to make a value for the result
    @State public var actualResult = "test"
    // dictionary for data base
    @State var people = ["name" : "Bounty" , "score" : "9/10"]
    
    // database test
    @ObservedObject var model = ViewModel()
    

    
    var scannerSheet : some View {
        CodeScannerView(
            codeTypes: [.qr, .code128, .ean13, .ean8],
            completion: { result in
                if case let .success(code) = result {
                    self.scannedCode = code.string
                    self.isPresentingScanner = false
                    
                    
                    // create link to database
                    // - done in above file
                     
                    //retrive all database info
                    model.getData()
                    //get the one i want
                    
                    
                }
            }
        )
    }
      

    var body: some View {
        VStack(spacing: 10) {
            
            
            Text(scannedCode)
            Text(actualResult)
            
            
            // test for database start
            List (model.list) { item in
                Text(item.name)
                Text(item.scannedCode2)
                Text(item.notes)
            }
            
            //end of test
            
            Button("Scan Code") {
                self.isPresentingScanner = true
            }
            
            .sheet(isPresented: $isPresentingScanner) {
                self.scannerSheet
            }
        }
    }
    
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
import Foundation
import Firebase
import FirebaseAnalytics
import FirebaseCore


class ViewModel: ObservableObject {
    
    @Published var list = [products]()
    
    func getData() {
        // get reference to the database
        let db = Firestore.firestore()
        
        //read the database in correct path
        db.collection("products").getDocuments { snapshot, error in
            
            //check for errors
            if error == nil {
                //no errors
                
                if let snapshot = snapshot {
                    
                    // Update the list property in the main thread
                    DispatchQueue.main.async {
                        
                        //get all the documents and create products
                        self.list = snapshot.documents.map { d in
                            
                            // Create a producs item for each document returned
                            return products(id: d.documentID,
                                            name: d["name"] as? String ?? "",
                                            scannedCode2: d["scannedCode2"] as? String ?? "",
                                            notes: d["notes"] as? String ?? "")
                        }
                    }
                }
            }
            else {
                // handle the error
            }
        }
    }
}
import Foundation


struct products: Identifiable {
    var id: String
    var name: String
    var scannedCode2: String
    var notes: String
}

This works I just want to change it so that I can use a variable

I can see that you have code to read data from Firebase but where is your code to write data to Firebase?

Also it’s spelled Xcode not “X - code”

1 Like

I don’t need it

Thank you for the input

@Toby

The call to Firebase to retrieve data from a collection has to be done using code such as you have in your getData() function.

You cannot specify a URL to point to a specific data property in a Firebase collection. You must use the Firebase API to retrieve records from the collection. That’s why you have a GoogleService-Info.plist file that you add you your project so that links the App to the Firebase Project to authenticate the App as the owner of the Data to which you require access to.

Does that help?

I understand that. this does not answer my question.

What I am asking is can I use a variable?

This is what you asked so I understood by pathway that you meant a url. If that’s not what you meant then rephrase your question.

class ViewModel: ObservableObject {
    
    @Published var list = [products]()
    
    func getData() {
        // get reference to the database
        let db = Firestore.firestore()
        
        //read the database in correct path
        db.collection("products").getDocuments { snapshot, error in
            
            //check for errors
            if error == nil {
                //no errors
                
                if let snapshot = snapshot {
                    
                    // Update the list property in the main thread
                    DispatchQueue.main.async {
                        
                        //get all the documents and create products
                        self.list = snapshot.documents.map { d in
                            
                            // Create a producs item for each document returned
                            return products(id: ContentView().scannedCode,
                                            name: d["name"] as? String ?? "")
                        }
                    }
                }
            }
            else {
                // handle the error
            }
        }
    }
}

I want to use the variable ‘scannedCode’ for the document ID but it doesn’t work

self.list = snapshot.documents.map { d in
                            
                            return products(id: ContentView().scannedCode,
                                            name: d["name"] as? String ?? "")

What’s wrong?

@Toby

Hi Toby,

I have created some code here using your ContentView, your ViewModel and Data model (Products) and added the CodeScanner (a Paul Hudson GitHub package which I assume is what you have used) and the scanner works.

(edit)
The method you need to use to read the data in Firebase is completely different to that which you are currently trying to use. The current getData() simply reads all the records in the database as opposed to performing a query based on a criteria.

This function will get you what you want by allowing you to pass in the code.string and that will query the database and extract the matching record.

    func lookupCode(barCode: String) {
        let db = Firestore.firestore()

        let query = db.collection("products").whereField("scannedCode2", isEqualTo: barCode)

        query.getDocuments { snapshot , error in
            guard error == nil else { return }
            if let snapshot = snapshot {
                for doc in snapshot.documents {
                    let newItem = products(id: doc.documentID,
                                           name: doc["name"] as? String ?? "",
                                           scannedCode2: doc["scannedCode2"] as? String ?? "",
                                           notes: doc["notes"] as? String ?? "")
                    DispatchQueue.main.async {
                        self.list.append(newItem)
                    }
                }
            }
        }
    }

The data I have set up makes use of the property scannedCode2 to store the barCode of the product hence the query specifying that field to search in.

In ContentView modify the CodeScannerView to this:

        CodeScannerView(
            codeTypes: [.qr, .code128, .ean13, .ean8],
            completion: { result in
                if case let .success(code) = result {
                    self.scannedCode = code.string
                    self.isPresentingScanner = false


                    // create link to database
                    // - done in above file

                    //retrive all database info
                    model.lookupCode(barCode: code.string)
                    //get the one i want

                }
            }
        )

@Chris_Parker

Hi Chris,

I implemented the code above and there are no errors but its not outputting anything.
How can I see the results?

this is what I had before to show the results

List (model.list) { item in
                Text(item.name)

what do I do?

Thanks

@Toby

There may be some subtle differences between the code I have and your project. It might be simpler to share your entire project so that I can see where those differences are.

I had to rename some of the things in your code so that it didn’t clash with existing code I had in my test project. Perhaps I missed something in the process.

Can you compress the entire project into a zip file and post that to either Dropbox or Google Drive. Then create a share link and post that link in a reply.

If you choose to use Google Drive then when you create the Share link, ensure that the “General Access” option is set to “Anyone with the Link” rather than “Restricted”.

@Chris_Parker

https://drive.google.com/file/d/1o9JAeL7xawNEroGiMedt6NJi9Ef_cM0m/view?usp=share_link

thanks