TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

SOLVED: How can I search in different columns in SwiftData Query?

Forums > SwiftUI

I have a question about SwiftData and the implementation presented by Paul in the iTour app @ SwiftData by Example I think I have understood this so far, but would now like to extend the app so that the user has the option of selecting, e.g. via a picker, in which element he wants to search. In the implementation shown by Paul, the searchString is passed and this is then processed in the init method:

init(sort: SortDescriptor<Destination>, searchString: String) {
        _destinations = Query(filter: #Predicate {
            if searchString.isEmpty {
                return true
            } else {
                return $0.name.localizedStandardContains(searchString)
            }
        }, sort: [sort])
    }

It searches in "name".

How would I have to extend the init method so that I could search in "name" or "details", for example?

The call is made in the ContentView:

DestinationListingView(sort: sortOrder, searchString: searchText)

In the ContentView, I would then create a second picker in the ".toolbar" where the user can choose between "name" and "details". Something like this:

@Environment(\.modelContext) var modelContext
@State private var searchText = ""
@State private var sortOrder = SortDescriptor(\DiversExp.purchaseDate, order: .reverse)
@State private var searchColumn = "Details"

var body: some View {
        NavigationStack(path: $path) {
            DestinationListingView(sort: sortOrder, searchString: searchText)
                .navigationTitle("iTour")
                .searchable(text: $searchText)
                .navigationDestination(for: Destination.self, destination: EditDestinationView.init)
                .toolbar {
                    Button("Add Destination", systemImage: "plus", action: addDestination)
                    Menu("Sort", systemImage: "arrow.up.arrow.down") {
                        Picker("Sort", selection: $sortOrder) {
                            Text("Name")
                                .tag(SortDescriptor(\Destination.name))

                            Text("Priority")
                                .tag(SortDescriptor(\Destination.priority, order: .reverse))

                            Text("Date")
                                .tag(SortDescriptor(\Destination.date))
                        }
                        .pickerStyle(.inline)
                    }
                    Menu("Search in", systemImage: "magnifyingglass") {
                        Picker("Suche in", selection: $searchColumn) {
                            Text("Name")
                                .tag("Name")
                            Text("Details")
                                .tag("Details")
                        }
                        .pickerStyle(.inline)
                    }
                }
        }
    }

Can anyone help me with the question of how I need to pass "searchColumn" to DestinationListingView and then process it correctly in the init method to apply the saerchString to different elements.

2      

It is as easy as adding OR to your predicate as follows:

init(sort: SortDescriptor<Destination>, searchString: String) {

        _destinations = Query(filter: #Predicate {

            if searchString.isEmpty {
                return true
            } else {
                // your search will return result if name contains match OR details contain match
                return $0.name.localizedStandardContains(searchString) || $0.details.localizedStandardContains(searchString)
            }
        },sort: [sort])
    }

And in this case you don't need to choose where to look for your search, it will seach in both places. I suppose from user experience side it is more friendly way to look for things than switching in every search...

2      

OK, thanks for the answer, that would be one possible way. However, I would then not have the option of selecting which field I want to search in, or have I overlooked something in the answer?

2      

Sorry but maybe I got something wrong? My logic is following. I use .searchable(text: $searchText) and type in the the text I am trying to search for example something related to Paris. If you use OR as in my case it will show all the records that contain Paris either in name or details which I guess is logical. If you use either detail or name search then without the choosing the proper field of search it will not show you desired result. Assume that you selected to search in details for Paris and you have no such record in details but only in name, so the search will show you nothing. Then you have to select to search in name and only then your record will pop up.

2      

I understand, that use cases maybe different. If you still need to use it for whatever reason you can do as follows (maybe to change it to enum later):

  1. Add extra parameter
DestinationListingView(sort: sortOrder, searchString: searchText, searchColumn: searchColumn)
  1. And modify your init to

    init(sort: SortDescriptor<Destination>, searchString: String, searchColumn: String) {
    
        _destinations = Query(filter: #Predicate {
    
            if searchString.isEmpty {
                return true
            } else if searchColumn == "Name" {
                return $0.name.localizedStandardContains(searchString)
            } else if searchColumn == "Details" {
                return $0.details.localizedStandardContains(searchString)
            } else {
                return true
            }
        },sort: [sort])
    }

2      

Ah, thank you - once again I was thinking too complicated - how annoying. I tried to incorporate searchColumn directly into "$0..." somehow - stupid of me. I didn't think of the simple possibility of an if statement with searchColumn. Thanks again, also for the hint with the OR, which as you correctly wrote is also logical for the iTour app. I have described my problem using the iTour app, but I would like to use it in my app, and I would like to search specifically in different areas of the list.

I wish you a few relaxing holidays, a Merry Christmas and a Happy New Year :-)

2      

We all tend to make things a bit more complicated at times :) and that's ok. Thank you so much, have a nice holiday too @ralfb1105 , Merry Christmas and a Happy New Year!!!

2      

Hacking with Swift is sponsored by RevenueCat.

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.