I have the following code:
type SearchReq struct {
PageSize int32
Offset int32
Zipcode string
PracticeType []string
TreatmentType []string
HasPhotos bool
LatLong GeoLocationInput
}
func buildSearchQuery(searchOptions *database.SearchReq) bson.D {
var filter bson.D
if searchOptions.Zipcode != "" {
filter = append(filter, bson.E{"zipcode", searchOptions.Zipcode})
}
if len(searchOptions.PracticeType) != 0 {
filter = append(filter, bson.E{"practicetypes", bson.E{"$all", searchOptions.PracticeType}})
}
if len(searchOptions.TreatmentType) != 0 {
filter = append(filter, bson.E{"treatments", bson.E{"$all", searchOptions.TreatmentType}})
}
if searchOptions.HasPhotos {
filter = append(filter, bson.E{"avatarurl", bson.E{"$ne", nil}})
}
return filter
}
One of the queries I'm trying to make looks like this:
db.providers.find({treatments: {$all: ["botox","not-botox"]}, zipcode: "90210"})
The filter prints out this:
1st run: [{zipcode 60010} {avatarurl {$ne <nil>}}]
2nd run: [{zipcode 90210} {treatments {$all [botox not-botox]}}]
That command line query pulls up results while to Go variant does not. I've tried switching it to a map but to no avail. What am I doing wrong here?
Ideally I'm trying to build a way of adding a set of criteria to one query.
PS. The records from the command linequery
{ "_id" : ObjectId("6001d1aab756f9540e8850ba"), "name" : "Mr. Brandy Emmerich", "accountnumber" : "b0c6ee03ab", "displayname" : "Mr. Brandy Emmerich", "streetaddress" : "92813 Funk Isle", "city" : "New Artville", "statename" : "Oklahoma", "zipcode" : "90210", "websiteurl" : "http://wildermannikolaus.org/robert.wolf", "emailaddress" : "hosea.runte@example.com", "telephonenumber" : "", "hours" : [ { "day" : 0, "open" : ISODate("2021-01-15T17:32:26.383Z"), "close" : ISODate("2021-01-15T17:32:26.383Z") }, { "day" : 1, "open" : ISODate("2021-01-15T17:32:26.383Z"), "close" : ISODate("2021-01-15T17:32:26.383Z") }, { "day" : 2, "open" : ISODate("2021-01-15T17:32:26.383Z"), "close" : ISODate("2021-01-15T17:32:26.383Z") }, { "day" : 3, "open" : ISODate("2021-01-15T17:32:26.383Z"), "close" : ISODate("2021-01-15T17:32:26.383Z") }, { "day" : 4, "open" : ISODate("2021-01-15T17:32:26.383Z"), "close" : ISODate("2021-01-15T17:32:26.383Z") }, { "day" : 5, "open" : ISODate("2021-01-15T17:32:26.383Z"), "close" : ISODate("2021-01-15T17:32:26.383Z") }, { "day" : 6, "open" : ISODate("2021-01-15T17:32:26.383Z"), "close" : ISODate("2021-01-15T17:32:26.383Z") } ], "instagramurl" : "https://instagram.com/ilene.kunde", "twitterurl" : "https://twitter.com/ilene.kunde", "facebookurl" : "https://facebook.com/ilene.kunde", "avatarurl" : "http://wehner.name/nick", "treatments" : [ "botox", "not-botox" ], "practicetypes" : null, "tags" : [ "", "", "", "id", "delectus", "pariatur" ], "metadata" : { "dolorem" : "excepturi", "numquam" : "at" }, "created_at" : ISODate("2021-01-15T17:32:26.383Z") }
{ "_id" : ObjectId("6001d1d0701489602c55f82a"), "name" : "Clara McLaughlin", "accountnumber" : "964a3de178", "displayname" : "Clara McLaughlin", "streetaddress" : "8708 Rodolfo Prairie", "city" : "Parisianburgh", "statename" : "West Virginia", "zipcode" : "90210", "websiteurl" : "http://pollich.org/kimberly_rau", "emailaddress" : "emiliano@example.org", "telephonenumber" : "", "hours" : [ { "day" : 0, "open" : ISODate("2021-01-15T17:33:04.526Z"), "close" : ISODate("2021-01-15T17:33:04.526Z") }, { "day" : 1, "open" : ISODate("2021-01-15T17:33:04.526Z"), "close" : ISODate("2021-01-15T17:33:04.526Z") }, { "day" : 2, "open" : ISODate("2021-01-15T17:33:04.526Z"), "close" : ISODate("2021-01-15T17:33:04.526Z") }, { "day" : 3, "open" : ISODate("2021-01-15T17:33:04.526Z"), "close" : ISODate("2021-01-15T17:33:04.526Z") }, { "day" : 4, "open" : ISODate("2021-01-15T17:33:04.526Z"), "close" : ISODate("2021-01-15T17:33:04.526Z") }, { "day" : 5, "open" : ISODate("2021-01-15T17:33:04.526Z"), "close" : ISODate("2021-01-15T17:33:04.526Z") }, { "day" : 6, "open" : ISODate("2021-01-15T17:33:04.526Z"), "close" : ISODate("2021-01-15T17:33:04.526Z") } ], "instagramurl" : "https://instagram.com/presley", "twitterurl" : "https://twitter.com/presley", "facebookurl" : "https://facebook.com/presley", "avatarurl" : "http://baumbach.com/minerva", "treatments" : [ "botox", "not-botox" ], "practicetypes" : null, "tags" : [ "", "", "", "corporis", "eveniet", "velit" ], "metadata" : { "enim" : "nisi" }, "created_at" : ISODate("2021-01-15T17:33:04.526Z") }
The problem is how you add composite filters. If they are not single values, e.g. you're using $all
or $ne
, you have to use "full" documents as their values. bson.E
is not a "full" document, it's just an element of a document. A full document is bson.D
or bson.M
.
So use this as your filter builder:
func buildSearchQuery(searchOptions *database.SearchReq) bson.D {
var filter bson.D
if searchOptions.Zipcode != "" {
filter = append(filter, bson.E{"zipcode", searchOptions.Zipcode})
}
if len(searchOptions.PracticeType) != 0 {
filter = append(filter, bson.E{"practicetypes", bson.D{{"$all", searchOptions.PracticeType}}})
}
if len(searchOptions.TreatmentType) != 0 {
filter = append(filter, bson.E{"treatments", bson.D{{"$all", searchOptions.TreatmentType}}})
}
if searchOptions.HasPhotos {
filter = append(filter, bson.E{"avatarurl", bson.D{{"$ne", nil}}})
}
return filter
}
Also note that if searchOptions
is empty the above will return nil
, which is invalid as a filter. Ensure it's initialized to a non-nil
empty slice. So instead of
var filter bson.D
Use
filter := bson.D{}
Also note that using bson.M
instead of bson.D
is simpler:
func buildSearchQueryMap(searchOptions *database.SearchReq) bson.M {
filter := bson.M{}
if searchOptions.Zipcode != "" {
filter["zipcode"] = searchOptions.Zipcode
}
if len(searchOptions.PracticeType) != 0 {
filter["practicetypes"] = bson.M{"$all": searchOptions.PracticeType}
}
if len(searchOptions.TreatmentType) != 0 {
filter["treatments"] = bson.M{"$all": searchOptions.TreatmentType}
}
if searchOptions.HasPhotos {
filter["avatarurl"] = bson.M{"$ne": nil}
}
return filter
}