heroiclabs / nakama

Distributed server for social and realtime games and apps.
https://heroiclabs.com
Apache License 2.0
8.97k stars 1.1k forks source link

Can't add collections with multiple values per key using nk.storage_write #297

Closed JapendWFM closed 5 years ago

JapendWFM commented 5 years ago

Description

When trying to add multiple items to a public colection in the server using an rcp call that is being called from a test html we found that the collection is created with the correct key, but with no value.

However, if we (using the same code) access one of the provided values (like data[1]), then hat value is written.

Steps to Reproduce

1. Send the payload:


const payload =
    {
        "password": "example_password",
        "items":
        [
          {
                  "key": "cars",
                  "data":[
                    {
                      "item_id": "CAR01",
                      "name": "FORMULA 1",
                      "price": 0,
                      "elo": 0,
                      "buy_only_once": true
                    },
                    {
                      "item_id": "CAR02",
                      "name": "HOTROD",
                      "price": 500,
                      "elo": 1100,
                      "buy_only_once": true
},
                    {
                    "item_id": "CAR03",
                      "name": "KART",
                      "price": 1000,
                      "elo": 1200,
                      "buy_only_once": true
                    },
                    {
                    "item_id": "CAR04",
                      "name": "MONSTER TRUCK",
                      "price": 1500,
                      "elo": 1300,
                      "buy_only_once": true
                    },
                    {
                    "item_id": "CAR05",
                      "name": "4x4",
                      "price": 2000,
                      "elo": 1400,
                      "buy_only_once": true
                    },
                    {
                    "item_id": "CAR06",
                      "name": "BULLDOZER",
                      "price": 2500,
                      "elo": 1500,
                      "buy_only_once": true
                    },
                  ],
              },    ]
    };
    const rpcId = "add_items";
    const respo = await client.rpc(responseSession, rpcId, payload);

2. In server, execute the function add_items. It will try to write and read afterwards, to check if everything went ok:

local function add_items(context, payload)
  local petition = nk.json_decode(payload)

  --Check password
  if(petition.password == glo.PASSWORD) then

    --Add every item to list
    for key, item in ipairs(petition.items) do
      newItem ={collection = glo.ITEM_COLLECTION_NAME, key = item.key, value = item.data, user_id = nil,  permission_read = 2, permission_write = 0}
      nk.storage_write({newItem})
    end

    local object_ids = {
      {collection = "virtualgoods", key = "cars", user_id = nil},
    }

    local objects = nk.storage_read(object_ids)
    --objects = nk.storage_read(object_ids)
    print(inspect(objects))

    return utils.create_json_response_for_rpc_function(SUCCES_CODE, SUCCESS_MEASSAGE, petition)
  else
    return utils.create_json_response_for_rpc_function(INTERNAL_SERVER_ERROR_CODE, INTERNAL_SERVER_ERROR_MESSAGE, petition)
  end
end
nk.register_rpc(add_items, 'add_items') 

3. Try again, but adding only one value this time

local function add_items(context, payload)

  local petition = nk.json_decode(payload)

  --Check password
  if(petition.password == glo.PASSWORD) then

    --Add every item to list
    for key, item in ipairs(petition.items) do
      newItem ={collection = glo.ITEM_COLLECTION_NAME, key = item.key, value = item.data[1], user_id = nil,  permission_read = 2, permission_write = 0}
      nk.storage_write({newItem})
    end

    local object_ids = {
      {collection = "virtualgoods", key = "cars", user_id = nil},
    }
    local objects = nk.storage_read(object_ids)
    --objects = nk.storage_read(object_ids)
    print(inspect(objects))

    return utils.create_json_response_for_rpc_function(SUCCES_CODE, SUCCESS_MEASSAGE, petition)
  else
    return utils.create_json_response_for_rpc_function(INTERNAL_SERVER_ERROR_CODE, INTERNAL_SERVER_ERROR_MESSAGE, petition)
  end
end
nk.register_rpc(add_items, 'add_items')

Expected Result

In step 2, collection with corresponding keys should contain all provided values. In step 3, collection with corresponding key should contain only one value.

Actual Result

For code in step 2:

nakama         | { {
nakama         |     collection = "virtualgoods",
nakama         |     create_time = 1550494126,
nakama         |     key = "cars",
nakama         |     permission_read = 2,
nakama         |     permission_write = 0,
nakama         |     update_time = 1550497547,
nakama         |     value = {},
nakama         |     version = "37a6259cc0c1dae299a7866489dff0bd"
nakama         |   } }

For code in step 3:

 { {
nakama         |     collection = "virtualgoods",
nakama         |     create_time = 1550494126,
nakama         |     key = "cars",
nakama         |     permission_read = 2,
nakama         |     permission_write = 0,
nakama         |     update_time = 1550500267,
nakama         |     value = {
nakama         |       buy_only_once = true,
nakama         |       elo = 0,
nakama         |       item_id = "CAR01",
nakama         |       name = "FORMULA 1",
nakama         |       price = 0
nakama         |     },
nakama         |     version = "58d76afd91b00a038cacb5b631024ad2"
nakama         |   } }

Your Environment

zyro commented 5 years ago

@JapendWFM If I understand your code correctly the loop below will execute only once for the sample input you provided:

    for key, item in ipairs(petition.items) do
      newItem ={collection = glo.ITEM_COLLECTION_NAME, key = item.key, value = item.data, user_id = nil,  permission_read = 2, permission_write = 0}
      nk.storage_write({newItem})
    end

And will attempt to write a single storage record with the key cars and the value [{"item_id":"CAR01",[...snip...]}].

Is this what you intended to do?

If so it won't quite work because the storage value you're attempting to write is a top-level JSON array ([]). The storage system currently only allows top-level JSON objects ({}).

JapendWFM commented 5 years ago

Yes, that is what I was intending to do with that code.

zyro commented 5 years ago

In that case I think this is a duplicate of the feature request in #304. Keep an eye on that, but until then you can change your data structure to be a top-level JSON object.