So I'm struggling to figure out how to sort following structure by "status" field (asc, desc)
type CampaignStatus struct {
Campaign CampaignData
Status string `json:"status" bson:"status"`
}
type CampaignsPagination struct {
Pagination PageMetadata `json:"pagination"`
Campaigns []CampaignStatus `json:"campaigns"`
}
Example json of full campaigns pagination:
"pagination": {
"page": 1,
"per_page": 15,
"page_count": 1,
"total_count": 4
},
"campaigns": [
{
"Campaign": {
"_id": "57597fc6799e0fe41d0eede6",
"name": "Test campaign",
"description": "Just test campaign"
"isEmail": true
},
"status": "expired"
},
...
}
So my function is retuting variable ret := &CampaignsPagination{} which is filled with data from mongoDB but status is determinated by other stuff in realtime. So reflect package is saying that I'm trying to sort type of *CampaignsPagination and everything what I use pretty much ends with errors like "type CampaignsPagination does not support indexing" (using sort packag) any hints are more then welcome
Update:
How I try to sort this (but it won't compile due to (type *CampaignsPagination does not support indexing
func (a *CampaignsPagination) Len() int {
return len(a)
}
func (a *CampaignsPagination) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}
func (a *CampaignsPagination) Less(i, j int) bool {
if a[i].Status < a[j].Status {
return true
}
if a[i].Status > a[j].Status {
return false
}
return a[i].Status < a[j].Status
}
Usually sorting is defined on a slice. You try to define sorting on your CampaignsPagination
struct type.
This can also be done, but it's a little unusal (e.g. what would you do if you decide you want to have another order based on another field?). Since your receiver a
is not a slice but a (pointer to a) wrapper struct, when indexing and returning the length, use the slice a.Campaigns
. Also string
values are comparable and ordered (lexically byte-wise). So you can simply compare CampaignStatus.Status
values and return the result in Less()
.
func (a *CampaignsPagination) Len() int {
return len(a.Campaigns)
}
func (a *CampaignsPagination) Swap(i, j int) {
a.Campaigns[i], a.Campaigns[j] = a.Campaigns[j], a.Campaigns[i]
}
func (a *CampaignsPagination) Less(i, j int) bool {
return a.Campaigns[i].Status < a.Campaigns[j].Status
}
A more logical solution would be to define the sorting on a slice, e.g.:
type CampaignStatusSort []CampaignStatus
func (c CampaignStatusSort) Len() int { return len(c) }
func (c CampaignStatusSort) Swap(i, j int) { c[i], c[j] = c[j], c[i] }
func (c CampaignStatusSort) Less(i, j int) bool { return c[i].Status < c[j].Status }
And then if you have a value of type *CampaignsPagination
, you can sort the campaigns like this:
cp := &CampaignsPagination{} // Init struct
sort.Sort(CampaignStatusSort(cp.Campaigns))
There is no one to one relationship between CampaignsPagination
and Status
. CampaignsPagination
has a slice of CampaignStatus
as a field; means CampaignsPagination
has many Status
es.
So I assume that you want to sort the field Campaigns []CampaignStatus
. Your code is almost correct; for CampaignsPagination
to implement the interface sort.Interface
:
func (x *CampaignsPagination) Len() int {
return len(x.Campaigns)
}
func (x *CampaignsPagination) Swap(i, j int) {
a := x.Campaigns
a[i], a[j] = a[j], a[i]
}
func (x *CampaignsPagination) Less(i, j int) bool {
a := x.Campaigns
if a[i].Status < a[j].Status {
return true
}
if a[i].Status > a[j].Status {
return false
}
return a[i].Status < a[j].Status
}
But it would be more logical to introduce a sortable type:
type Statuses []CampaignStatus
func (a Statuses) Len() int {
return len(a)
}
func (a Statuses) Swap(i, j int) {
a[i], a[j] = a[j], a[i]
}
func (a Statuses) Less(i, j int) bool {
if a[i].Status < a[j].Status {
return true
}
if a[i].Status > a[j].Status {
return false
}
return a[i].Status < a[j].Status
}
And then use this as the field Campaigns
:
type CampaignsPagination struct {
Pagination PageMetadata `json:"pagination"`
Campaigns Statuses `json:"campaigns"`
}