From 12c731f6b8a97d78e267ebb659f78fc5a85f35f2 Mon Sep 17 00:00:00 2001 From: nguyenhuuhien22072001 <63991051+nguyenhuuhien22072001@users.noreply.github.com> Date: Sun, 24 Sep 2023 23:32:52 +0700 Subject: [PATCH] handle sort elasticsearch --- elasticsearch.go | 20 ++++++++++++++-- query.go | 59 ++++++++++++++++++++++++++++++++++++++++------- search_builder.go | 2 +- 3 files changed, 70 insertions(+), 11 deletions(-) diff --git a/elasticsearch.go b/elasticsearch.go index 7b7d8d2..4b03093 100644 --- a/elasticsearch.go +++ b/elasticsearch.go @@ -246,7 +246,8 @@ func FindAndDecode(ctx context.Context, es *elasticsearch.Client, indexName []st return false, err } defer res.Body.Close() - + + modelType := reflect.TypeOf(result).Elem().Elem() if res.IsError() { return false, errors.New("response error") } else { @@ -255,7 +256,22 @@ func FindAndDecode(ctx context.Context, es *elasticsearch.Client, indexName []st return false, err } else { hits := r["hits"].(map[string]interface{})["hits"].([]interface{}) - if err := json.NewDecoder(esutil.NewJSONReader(hits)).Decode(&result); err != nil { + listResults := make([]interface{}, 0) + for _, hit := range hits { + r := hit.(map[string]interface{})["_source"] + r.(map[string]interface{})["id"] = hit.(map[string]interface{})["_id"] + stValue := reflect.New(modelType).Elem() + for i := 0; i < modelType.NumField(); i++ { + field := modelType.Field(i) + if value, ok := r.(map[string]interface{})[field.Name]; ok { + stValue.Field(i).Set(reflect.ValueOf(value)) + } + } + listResults = append(listResults, r) + } + + err := json.NewDecoder(esutil.NewJSONReader(listResults)).Decode(result) + if err != nil { return false, err } return true, nil diff --git a/query.go b/query.go index f336d30..73f7f89 100644 --- a/query.go +++ b/query.go @@ -11,7 +11,7 @@ import ( "strings" ) -func BuildSearchResult(ctx context.Context, db *elasticsearch.Client, results interface{}, indexName string, query map[string]interface{}, sort []string, limit int64, offset int64, modelType reflect.Type, options ...func(context.Context, interface{}) (interface{}, error)) (int64, error) { +func BuildSearchResult(ctx context.Context, db *elasticsearch.Client, results interface{}, indexName string, query map[string]interface{}, sort []map[string]interface{}, limit int64, offset int64, modelType reflect.Type, options ...func(context.Context, interface{}) (interface{}, error)) (int64, error) { var mp func(context.Context, interface{}) (interface{}, error) if len(options) > 0 { mp = options[0] @@ -20,10 +20,10 @@ func BuildSearchResult(ctx context.Context, db *elasticsearch.Client, results in from := int(offset) size := int(limit) fullQuery := UpdateQuery(query) + fullQuery["sort"] = sort req := esapi.SearchRequest{ Index: []string{indexName}, Body: esutil.NewJSONReader(fullQuery), - Sort: sort, From: &from, Size: &size, } @@ -44,9 +44,11 @@ func BuildSearchResult(ctx context.Context, db *elasticsearch.Client, results in hits := r["hits"].(map[string]interface{})["hits"].([]interface{}) count = int64(r["hits"].(map[string]interface{})["total"].(map[string]interface{})["value"].(float64)) listResults := make([]interface{}, 0) + idField := modelType.Field(0) + jsonID := idField.Tag.Get("json") for _, hit := range hits { r := hit.(map[string]interface{})["_source"] - r.(map[string]interface{})["id"] = hit.(map[string]interface{})["_id"] + r.(map[string]interface{})[jsonID] = hit.(map[string]interface{})["_id"] stValue := reflect.New(modelType).Elem() for i := 0; i < modelType.NumField(); i++ { field := modelType.Field(i) @@ -71,8 +73,8 @@ func BuildSearchResult(ctx context.Context, db *elasticsearch.Client, results in } } -func BuildSort(s string) []string { - var sort []string +func BuildSort(s string, modelType reflect.Type) []map[string]interface{} { + sort := []map[string]interface{}{} if len(s) == 0 { return sort } @@ -80,14 +82,55 @@ func BuildSort(s string) []string { for i := 0; i < len(sorts); i++ { sortField := strings.TrimSpace(sorts[i]) fieldName := sortField + + var mapFieldName map[string]interface{} c := sortField[0:1] if c == "-" || c == "+" { - fieldName = sortField[1:] + //fieldName = sortField[1:] + field, ok := getFieldName(modelType, sortField[1:]) + if !ok { + return []map[string]interface{}{} + } + fieldName = field if c == "-" { - fieldName += ":desc" + mapFieldName = map[string]interface{}{ + fieldName: map[string]string{ + "order": "desc", + }, + } + } else { + mapFieldName = map[string]interface{}{ + fieldName: map[string]string{ + "order": "asc", + }, + } } } - sort = append(sort, fieldName) + sort = append(sort, mapFieldName) } + return sort } + +func getFieldName(structType reflect.Type, jsonTagValue string) (string, bool) { + var ( + bsonTagValue string + typeField reflect.Kind + ) + for i := 0; i < structType.NumField(); i++ { + field := structType.Field(i) + jsonTag := field.Tag.Get("json") + if jsonTag == jsonTagValue { + bsonTagValue = field.Tag.Get("bson") + typeField = field.Type.Kind() + break + } + } + if bsonTagValue != "_id" { + if typeField == reflect.String { + return "", false + } + return jsonTagValue, true + } + return bsonTagValue, true +} diff --git a/search_builder.go b/search_builder.go index 48f5958..2fc1e8b 100644 --- a/search_builder.go +++ b/search_builder.go @@ -29,7 +29,7 @@ func NewSearchQuery(client *elasticsearch.Client, indexName string, modelType re func (b *SearchQuery) Search(ctx context.Context, sm interface{}, results interface{}, pageSize int64, skip int64) (int64, error) { query := b.BuildQuery(sm) s := b.GetSort(sm) - sort := BuildSort(s) + sort := BuildSort(s, b.ModelType) total, err := BuildSearchResult(ctx, b.Client, results, b.IndexName, query, sort, pageSize, skip, b.ModelType, b.Map) return total, err }