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.
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?
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.
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.
//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
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.
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 ?? "")
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
}
}
)
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”.