How do I update data in LDT (LLIST)?

llist
ldt

#1

Sorry, just starting out in aerospike. Great product though.

I am using the PHP client.

I am inserting some data in LList bin.

namespace - test

set - orders

Key - KS01

bin - purchase

data - {key:0,id:3451,value:76}

How can I update just the “value” as the “add” function throws a “Unique key or value violation”.

Do I need to delete this first and do a “add” as the api does not have any function for updating.

Also, when I check in AQL, the purchase bi is empty. Am I doing something wrong.

SELECT * FROM test.orders WHERE PK='KS01';

The purchase field is blank.

https://github.com/aerospike/aerospike-client-php/blob/master/doc/aerospike_llist.md

Please let me know.

Thanks, Pushpesh


#2

LLIST has update and update_all intefaces. PHP client does not seem to be exposing that interface. The actual code would look like

public function updateMany(array $values) {
    $status = $this->db->apply($this->key, 'llist', 'update_all', array($this->bin, $values));
    $this->processStatusCode($status);
    return $this->errorno;
}

public function update($value) {
     if (!is_string($value) && !is_int($value) && !is_array($value)) {
         $this->errorno = self::ERR_INPUT_PARAM;
         $this->error = self::MSG_TYPE_NOT_SUPPORTED;
         return $this->errorno;
    }
    $status = $this->db->apply($this->key, 'llist', 'update', array($this->bin, $value));
    $this->processStatusCode($status);
    return $this->errorno;
}

If you have php client code handy you should be able to add this to $PHPCLIENT/LDT/LList.php and build.

Other option would be to use apply and directly invoke LLIST udf (LLIST is a UDF module) The parameter as you can see above are array of values of update_all and a single value of update

– R


#3

Hi Raj,

Thanks for your reply. I will check this and let you know.

Also, can you please help with the above query with the example I posted above.

When will it reflect in the php client api.

Thanks


#4

The original value in my bin is {key:0,id:3451,value:76}. If I use the update method and want to update just the value…what would the $value value be?


#5

New value would be

{key:0,id:3451,value:86}

Key and id remaining the same only value part should have new data. In aql command would look like.

aql > execute llist.update('llistbin', 'JSON{"key":0, "id":3451, "value":86}') on test.demo where PK='1'

– R


#6

oh ok…means I need to pass all the key-value pairs even though I need to update just one of them.

Then that would mean, I need to scan the bin for this key (0), get all data and then update the value on the required data and then push it back.

Please let me know if that’s correct.

Seems a bit of overhead for a simple update.

Also, I am not seeing any data in my bin in AQL, even though it shows via the php code. Please help


#7

LLIST bin essentially stores KEY->VALUE pair (Implemented as B+tree in server). When you pass a map type data to LLIST, it looks for keyword key and uses it as KEY sort and passed in data in entirety as VALUE.

Now if you want to update something in the LLIST you need to specify KEY and VALUE. There is no notion of updating only subpart of VALUE.

What you are trying to do would in logic look like

  • oldValue = llist.find(key)
  • newValue = updateValue(oldValue)
  • llist.update(newValue)

which has fundamental problem of two round trips to the server and performing IO twice.

This can be worked around by using UDF which would look like.

listExtention.lua

local llist = required('ldt/lib_llist')
function findAndUpdate(rec, listBin, key, setValue)
    if (llist.ldt_exists(rec, listBin)) then
        return 1;
    end

    local rc = 1; 
    local oldValue = llist.find(rec, listBin, key)
    if (oldValue ~= nil) then
       oldValue['value'] = setValue;
       rc = llist.update(rec, listBin, oldValue);
    end
    return rc;
end

This function would return 0 in case of success and nonzero in case of failure.

Invocation of this from aql would look like

aql > register module 'listExtension.lua'
aql > execute findAndUpdate('mylist', 0, 86) on test.demo where PK='1'

Note: first parameter which is rec is implicit in UDF system passes it. Others you have to pass.

– R


#8
findAndUpdate('mylist', 0, 86)

How does the UDF know, it has to update 86 in the “value” field and not in any other field, say “id”?

The UDF that you created, only updates the value field. Can we pass the bin’s key to UDF as well so that the parameter which needs to be updated is dynamic.

I mean

findAndUpdate('mylist', 0, 86, 'value') // last parameter is the key which needs to be updated

Just want to understand how it works so that I can write my wrapper correctly.

Thanks for the help.


#9

Send me a pull request to aerospike/aerospike-client-php when you’re done :wink:, otherwise I’ll update this in the LDT library of the client shortly.


#10

Hi Ronen,

Wish I could do that. A learning curve so far…

But please help me with the issue above. Is the method proposed by Raj above the only solution?

I want this in PHP only. So, should i do a scan and then update the result and then do update?

Please let me know.

Thanks


#11

You can pass anything you want to pass to UDF. For example if your entry were {key:0, v1:1, v2:2, v3:3) you can pass newValueMap = {v1:10, v2:30} to indicate set v1’s new value as 10 and v2’s new value as 30.

– R


#12

The new PHP client release (3.3.10) has the update methods implemented. It’s up to speed with the latest LList functionality:


#13

Further LList updates are part of release 3.4.3.