0

For a given id which is my primary key I want to append data to a List type if id is already present , if not then I want to create new List.

Here is my aerospike schema -

Column1: columnname=id; columntype=Integer; columnconstraint=primarykey
Column2: columnname=mylist; columntype=List<String>

Below is my POJO :

public class AeroSpikeModel {

    @Id
    private Integer id;

    private List<String> myList = new ArrayList<>();

   //getter and setter
}

Here is my DAO:

@Component
public class MyDAO {

    @Autowired
    private AerospikeRepository<AeroSpikeModel, Integer> aerospikeRepository;

    public void save(List<AeroSpikeModel> model) {
        aerospikeRepository.save(model);
     }

    public AeroSpikeModel get(Integer id) {
        return aerospikeRepository.findOne(id);
    }

}

The problem is every time I insert with an existing id it overwrites the list instead of appending to the existing list. How do I achieve the same , as aerospike natively supports appending to list

Manas Saxena
  • 2,171
  • 6
  • 39
  • 58

1 Answers1

0

@Document annotated classed are generic entities for saving any data into the storage, so it does not use data type specific operations.

In case you want to work directly with lists you should be using raw aerospike client API for now. Here is an example how this can be done in Java: https://github.com/aerospike/aerospike-client-java/blob/master/examples/src/com/aerospike/examples/OperateList.java#L53

There is another solution using spring-data-aerospike, but it won't be such effective as working directly with list append operation as you will need to firstly retrieve data, modify it and then save.

import lombok.Builder;
import lombok.Data;
import org.springframework.data.aerospike.mapping.Document;

    @Document
    @Data
    @Builder(toBuilder=true)
    public static class MyDocument {
        @Id
        public final long id;
        public final Set<String> items;
        public final String someString;
// Stores document version in this field. 
// In Aerospike terms it is referred to as generation. 
// Without this field CAS (compare-and-set) algorithm won't take place in spring-data
        @Version
        public long version;

    public static class MyDocumentBuilder {
        public MyDocumentBuilder addItem(String item) {
            this.items.add(item);
            return this;
        }
    }
}
import org.springframework.data.aerospike.repository.AerospikeRepository;

public interface MyDocumentRepository extends AerospikeRepository<MyDocument, Long> {

}
import lombok.RequiredArgsConstructor;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.retry.annotation.Retryable;

@RequiredArgsConstructor
public class MyDocumentService {

  private final MyDocumentRepository repo;

  // in case version of the document was modified on server -- 
  // we will need to retry our operation from the beginning
  @Retryable(OptimisticLockingFailureException.class)
  public boolean addToCollection(Long id, String itemToAdd) {
    return repo.findById(id)
                .map(found -> updateAndSave(found, itemToAdd))
                .orElse(false);
  }

  private boolean updateAndSave(MyDocument existing, String itemToAdd) {
    MyDocument updated = existing.toBuilder()
            .addItem(itemToAdd)
            .build();
    repo.save(updated);
  }
}

I've added @Version field and @Retryable so that in case you have multiple concurrently running updates on server you won't loose some of the updates. This algorithm is known as CAS (you can read more information about this here: What is CAS in NoSQL and how to use it? )