skip to Main Content

I’m using this function to get orders by status, the problem with this function is that the filtering happens after I get all my orders from redis is there a way to filter by value redis-side like in Postgres (a where statement for example) or does redis not support that?

func (r *queryResolver) OrdersByStatus(ctx context.Context, status string) ([]*models.Order, error) {
    defer utils.Elapsed("redis query => orders")()

    myCtx := ctx.Value(constants.KMyContext).(types.MyCtx)

    sessionData, sessionErr := session.GetSessionData(myCtx.ResponseWriter, myCtx.Request, constants.KCurrentUser)

    if sessionErr != nil {
        return nil, sessionErr
    }

    marshalledStories, err := cache.RedisClient.Get(ctx, constants.KOrders+sessionData.UUID).Result()
    if err != nil {
        log.Println("redis get err", err)
        return nil, errors.New(constants.InternalServerError)
    }
    var orders []*models.Order

    unmarshallErr := json.Unmarshal([]byte(marshalledStories), &orders)

    if unmarshallErr != nil {
        log.Println("redis unmarshallErr", unmarshallErr)
        return nil, errors.New(constants.InternalServerError)
    }

    var filtered []*models.Order

    for _, u := range orders {
        if u.Status == status {
            filtered = append(filtered, u)
        }
    }

    return filtered, nil
}

2

Answers


  1. The closest you could get since you are storing a serialized JSON array at a single key is to run a Lua script using EVAL that parses the JSON stored at the key, filters the entries based on the status value, and then re-serializes and saves the results either at the same key or a different key. This would be faster in that it would be executed entirely on the Redis server, but it is also harder to debug / more error-prone.

    You can use cjson.decode to parse JSON and cjson.encode to re-serialize it.

    Something like this:

    local myKey = KEYS[1]
    local status = ARGV[1]
    
    local raw = redis.call("GET", myKey)
    local orders = cjson.decode(raw)
    local filteredOrders = {}
    local index = 1
    
    for order, _ in ipairs(orders) do
      if order["status"] == status then
        filteredOrders[index] = order
        index = index + 1
      end
    end
    
    local resultRaw = cjson.encode(filteredOrders)
    redis.call("SET", myKey, resultRaw)
    
    Login or Signup to reply.
  2. I would use https://github.com/tidwall/gjson to query the marshalledStories

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search