Java DynamoDB: Add Items without Declaring Fields in an Entity Class

165 views Asked by At

The following example will map and adds Items into a DynamoDB Table. I thought the purpose of NoSQL is allow fields without specifying the Structure/types in a data structure entity.

How can I add fields into DynamoDB without specifying actual EntityType? (in this case, "Person" Entity class). Prefer to setup Postman to allow random Json elements .

I want to add any field in this Json, which are not in the Entity class. For example, "StreetAddress", "Car", "phoneNumber",

DynamoDBConfig

@RequiredArgsConstructor
@Configuration
public class DynamoDbConfig {

    @Bean
    public DynamoDBMapperConfig dynamoDBMapperConfig() {
        return DynamoDBMapperConfig.DEFAULT;
    }

    @Bean
    public DynamoDBMapper mapper() {
        return new DynamoDBMapper(amazonDynamoDBConfig());
    }

    @Bean
    public AmazonDynamoDB amazonDynamoDBConfig() {
        return AmazonDynamoDBClientBuilder.standard()
                .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration("dynamodb.us-west-2.amazonaws.com", "us-west-2"))
                .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("TestExample", "ExampleExample")))
                .build();
    }
}

Entity

@Data
@AllArgsConstructor
@NoArgsConstructor
@DynamoDBTable(tableName="person")
public class Person implements Serializable {
    @DynamoDBHashKey(attributeName = "personId")
    @DynamoDBAutoGeneratedKey
    private String personId;

    @DynamoDBAttribute
    private String name;

    @DynamoDBAttribute
    private int age;

    @DynamoDBAttribute
    private String email;
}

Controller:

@RestController
@RequestMapping("/api")
@CrossOrigin
public class PersonController {
    private PersonRepository repository;

    @Autowired
    public PersonController(PersonRepository repository) {
        this.repository = repository;
    }

    @PostMapping("/savePerson")
    public Person savePerson(@RequestBody Person person) {
        return repository.addPerson(person);
    }
}

Repository:

@Repository
public class PersonRepository {
    private DynamoDBMapper mapper;

    @Autowired
    public PersonRepository(DynamoDBMapper mapper) {
        this.mapper = mapper;
    }

    public Person addPerson(Person person) {
        mapper.save(person);
        return person;
    }
}

Test in Postman:

I want to add any field in this Json, which are not in the Entity class. For example, StreetAddress, Car, phoneNumber,

enter image description here

2

There are 2 answers

3
Dilermando Lima On BEST ANSWER

You can insert values into table by dynamic AttributeValue

import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.model.AttributeValue;


@Service
public class DynamoService {

    @Autowired AmazonDynamoDB amazonDynamoClient;

    public void putItemByMap(String nameTable, Map<String,String> values){

        Map<String,AttributeValue> mapValuesToBePut = 
               values.entrySet()
                     .stream()
                     .collect(Collectors.toMap(
                        Map.Entry::getKey, entry -> new AttributeValue(entry.getValue()))
                      );

        amazonDynamoClient.putItem(nameTable, mapValuesToBePut);
    }
}


4
Leeroy Hannigan On

It's not clear what behaviour you want exactly but I believe that DynamoDBIgnore will suit your requirements:

Indicates to the DynamoDBMapper instance that the associated property should be ignored. When saving data to the table, the DynamoDBMapper does not save this property to the table.

Applied to the getter method or the class field for a non-modeled property. If the annotation is applied directly to the class field, the corresponding getter and setter must be declared in the same class

https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.Annotations.html#DynamoDBMapper.Annotations.DynamoDBIgnore

Edit

If you want to add attributes to your DynamoDB item which are not modelled in your class, then you must use the lower level client. Or perhaps the Document client can give you some of that higher level abstraction while still allowing the flexibility.