# Multiple operations on CDT return the result of the last operation only

**URL:** https://discuss.aerospike.com/t/multiple-operations-on-cdt-return-the-result-of-the-last-operation-only/3385
**Category:** Ruby Client
**Tags:** query, cdt
**Created:** [September 12, 2016, 8:21am UTC](https://discuss.aerospike.com/t/multiple-operations-on-cdt-return-the-result-of-the-last-operation-only/3385 "2016-09-12T08:21:42Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![zingoba](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.aerospike.com/zingoba/32/605_2.png) [@zingoba](https://discuss.aerospike.com/u/zingoba)
#### Post date: [September 12, 2016, 8:21am UTC](https://discuss.aerospike.com/t/multiple-operations-on-cdt-return-the-result-of-the-last-operation-only/3385/1 "2016-09-12T08:21:43Z")

</div>

Hi,

We need to do multiple operations on a large hashmap bin; essentially, multiple get by keys. The keys are in no order lexicographically. So we send multiple get\_key operations on the same bin with different keys but contrary to the expectation the result contains the value for just the last operation and not the values for all the keys.

```
client.put(key, {'map' => {'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4}})
ops = []
ops << CDT::MapOperation.get_key('map', 'a', return_type: 8) # MapReturnType::KEY_VALUE
ops << CDT::MapOperation.get_key('map', 'b', return_type: 8)
ops << CDT::MapOperation.get_key('map', 'c', return_type: 8)
result = client.operate(key, ops)

```

Expectation : `result.bins` to be `{'map' => {'a' => 1, 'b' => 2, 'c' => 3}}`

What really happens is that `result.bins` contains only the value for the last operation i.e. `{'map' => {'c' => 3}}`.

This thing happens for list data type as well. We tried doing these same operations using the java client and the returned data is correct for both map and list. In ruby only the last operation is returned.

@Jan Please, help 🙂

---

<div class="post-metadata">

### Author: ![Jan](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.aerospike.com/jan/32/1124_2.png) [@Jan](https://discuss.aerospike.com/u/Jan)
#### Post date: [September 13, 2016, 5:59am UTC](https://discuss.aerospike.com/t/multiple-operations-on-cdt-return-the-result-of-the-last-operation-only/3385/2 "2016-09-13T05:59:55Z")

</div>

@zingoba,

The different Aerospike clients are unfortunately not consistent in this behaviour. The server actually returns the values for all operations, but the Ruby client currently only retains the last value when it aggregates all the values into the result Hash map.

I’m thinking of adopting the Java client behaviour of simply wrapping multiple values for the same bin name in an array. This would be a fairly easy change to make. There are some draw backs to this approach, esp. that it would be difficult to tell whether a returned array value is the result of a single operation or multiple operations that got combined. The alternative would be to use a true multimap implementation [1].

If you don’t mind, can you please open a feature request at our [Github repo](https://github.com/aerospike/aerospike-client-ruby/issues) and I will consider this for the next release.

Cheers, Jan

[1] [multimap | RubyGems.org | your community gem host](https://rubygems.org/gems/multimap)

---

<div class="post-metadata">

### Author: ![zingoba](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.aerospike.com/zingoba/32/605_2.png) [@zingoba](https://discuss.aerospike.com/u/zingoba)
#### Post date: [September 14, 2016, 11:47pm UTC](https://discuss.aerospike.com/t/multiple-operations-on-cdt-return-the-result-of-the-last-operation-only/3385/3 "2016-09-14T23:47:35Z")

</div>

Hi,

I have overridden the `parse_record` method for the `OperateCommand` class to maintain a list of operations performed for each of the bins as follows :

```
class Aerospike::OperateCommand < Aerospike::ReadCommand
  def parse_record(op_count, field_count, generation, expiration)
    bins = op_count > 0 ? {} : nil
    receive_offset = 0

    if field_count > 0
      i = 0
      while i < field_count
        field_size = @data_buffer.read_int32(receive_offset)
        receive_offset += (4 + field_size)
        i = i.succ
      end
    end

    i = 0
    while i < op_count
      op_size = @data_buffer.read_int32(receive_offset)
      particle_type = @data_buffer.read(receive_offset+5).ord
      name_size = @data_buffer.read(receive_offset+7).ord
      name = @data_buffer.read(receive_offset+8, name_size).force_encoding('utf-8')
      receive_offset += 4 + 4 + name_size

      particle_bytes_size = op_size - (4 + name_size)
      value = Aerospike.bytes_to_particle(particle_type, @data_buffer, receive_offset, particle_bytes_size)
      receive_offset += particle_bytes_size
      bins[name] ||= []
      bins[name] << value
      i = i.succ
    end
    bins = Hash[bins.map do |name, value|
      [name, value.size == 1 ? value.first : value]
    end]

    Record.new(@node, @key, bins, generation, expiration)
  end
end

```

This behaves in line with the java client.

---

<div class="post-metadata">

### Author: ![Jan](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.aerospike.com/jan/32/1124_2.png) [@Jan](https://discuss.aerospike.com/u/Jan)
#### Post date: [September 15, 2016, 4:19am UTC](https://discuss.aerospike.com/t/multiple-operations-on-cdt-return-the-result-of-the-last-operation-only/3385/4 "2016-09-15T04:19:59Z")

</div>

Himanshu, I’ll include a similar change in the next Ruby client update. (Probably some time next week.)

Cheers, Jan

---

<div class="post-metadata">

### Author: ![Jan](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.aerospike.com/jan/32/1124_2.png) [@Jan](https://discuss.aerospike.com/u/Jan)
#### Post date: [September 20, 2016, 2:09am UTC](https://discuss.aerospike.com/t/multiple-operations-on-cdt-return-the-result-of-the-last-operation-only/3385/5 "2016-09-20T02:09:58Z")

</div>

v2.2.0 is out on [RubyGems.org](https://rubygems.org/gems/aerospike) now.

You will need to pass an [`OperatePolicy`](https://github.com/aerospike/aerospike-client-ruby/blob/master/docs/policies.md#operatepolicy-object) with `record_bin_multiplicity` set to the value [`RecordBinMultiplicity::ARRAY`](https://github.com/aerospike/aerospike-client-ruby/blob/master/docs/policies.md#recordbinmultiplicity-values) on your `Client#operate` call in order to receive all results for multiple read operations on the same record bin.

Example:

```auto
require 'aerospike'
include Aerospike
client = Client.new()
key = Key.new('test', 'test', 'map')
client.put(key, {'map' => {'a' => 4, 'b' => 3, 'c' => 2, 'd' => 1}})
return_type = CDT::MapReturnType::VALUE
ops = []
ops << CDT::MapOperation.get_index('map', 0, return_type: return_type)
ops << CDT::MapOperation.get_by_rank('map', 0, return_type: return_type)
result = client.operate(key, ops)
result.bins // => { "map" => [1] }
policy = OperatePolicy.new(record_bin_multiplicity: RecordBinMultiplicity::ARRAY)
result = client.operate(key, ops, policy)
result.bins // => { "map" => [4, 1] }

```

Cheers, Jan
