Support of Azure Cosmos DB for Spring Data

CAST supports Azure Cosmos DB via its com.castsoftware.nosqljava extension. Details about how this support is provided for Spring Data source code is discussed below.

Supported Client Libraries

Library Version Supported
Azure spring data cosmos Up to: 3.10.0 ✔️

Supported Operations

Operations Method Supported
Insert org.springframework.data.repository.CrudRepository.save
org.springframework.data.repository.CrudRepository.saveAll
org.springframework.data.repository.reactive.ReactiveCrudRepository.save
org.springframework.data.repository.reactive.ReactiveCrudRepository.saveAll
com.microsoft.azure.spring.data.cosmosdb.repository.DocumentDbRepository.save
com.microsoft.azure.spring.data.cosmosdb.repository.DocumentDbRepository.saveAll
com.microsoft.azure.spring.data.cosmosdb.repository.CosmosRepository.save
com.microsoft.azure.spring.data.cosmosdb.repository.CosmosRepository.saveAll
com.microsoft.azure.spring.data.cosmosdb.repository.ReactiveCosmosRepository.save
com.microsoft.azure.spring.data.cosmosdb.repository.ReactiveCosmosRepository.saveAll
com.azure.spring.data.cosmos.repository.CosmosRepository.save
com.azure.spring.data.cosmos.repository.CosmosRepository.saveAll
com.azure.spring.data.cosmos.repository.ReactiveCosmosRepository.save
com.azure.spring.data.cosmos.repository.ReactiveCosmosRepository.saveAll
com.microsoft.azure.spring.data.cosmosdb.core.CosmosTemplate.insert
com.microsoft.azure.spring.data.cosmosdb.core.ReactiveCosmosTemplate.insert
Select org.springframework.data.repository.CrudRepository.existsById
org.springframework.data.repository.CrudRepository.findAll
org.springframework.data.repository.CrudRepository.findById
org.springframework.data.repository.PagingAndSortingRepository.findAll
org.springframework.data.repository.reactive.ReactiveCrudRepository.existsById
org.springframework.data.repository.reactive.ReactiveCrudRepository.findAll
org.springframework.data.repository.reactive.ReactiveCrudRepository.findAllById
org.springframework.data.repository.reactive.ReactiveCrudRepository.findById
org.springframework.data.repository.reactive.ReactiveSortingRepository.findAll
com.azure.spring.data.cosmos.repository.CosmosRepository.findById
com.azure.spring.data.cosmos.repository.CosmosRepository.findAll
com.azure.spring.data.cosmos.repository.CosmosRepository.existsById
com.azure.spring.data.cosmos.repository.CosmosRepository.count
com.azure.spring.data.cosmos.repository.CosmosRepository.findAllById
com.azure.spring.data.cosmos.repository.ReactiveCosmosRepository.findbyId
com.azure.spring.data.cosmos.repository.ReactiveCosmosRepository.findAll
com.azure.spring.data.cosmos.repository.ReactiveCosmosRepository.existsById
com.azure.spring.data.cosmos.repository.ReactiveCosmosRepository.count
com.azure.spring.data.cosmos.repository.ReactiveCosmosRepository.findAllById
com.microsoft.azure.spring.data.cosmosdb.repository.CosmosRepository.findById
com.microsoft.azure.spring.data.cosmosdb.repository.CosmosRepository.findAll
com.microsoft.azure.spring.data.cosmosdb.repository.CosmosRepository.existsById
com.microsoft.azure.spring.data.cosmosdb.repository.CosmosRepository.findAllById
com.microsoft.azure.spring.data.cosmosdb.repository.CosmosRepository.count
com.microsoft.azure.spring.data.cosmosdb.repository.DocumentDbRepository.findAll
com.microsoft.azure.spring.data.cosmosdb.repository.DocumentDbRepository.existsById
com.microsoft.azure.spring.data.cosmosdb.repository.DocumentDbRepository.findAllById
com.microsoft.azure.spring.data.cosmosdb.repository.DocumentDbRepository.count
com.microsoft.azure.spring.data.cosmosdb.repository.ReactiveSortingRepository.findAll
com.microsoft.azure.spring.data.cosmosdb.core.CosmosOperations.findAll
com.microsoft.azure.spring.data.cosmosdb.core.CosmosOperations.find
com.microsoft.azure.spring.data.cosmosdb.core.CosmosOperations.findByIds
com.microsoft.azure.spring.data.cosmosdb.core.CosmosOperations.exists
com.microsoft.azure.spring.data.cosmosdb.core.CosmosOperations.count
com.microsoft.azure.spring.data.cosmosdb.core.CosmosOperations.findById
com.microsoft.azure.spring.data.cosmosdb.core.CosmosTemplate.findById
com.microsoft.azure.spring.data.cosmosdb.core.ReactiveCosmosOperations.findAll
com.microsoft.azure.spring.data.cosmosdb.core.ReactiveCosmosOperations.find
com.microsoft.azure.spring.data.cosmosdb.core.ReactiveCosmosOperations.findByIds
com.microsoft.azure.spring.data.cosmosdb.core.ReactiveCosmosOperations.exists
com.microsoft.azure.spring.data.cosmosdb.core.ReactiveCosmosOperations.count
com.microsoft.azure.spring.data.cosmosdb.core.ReactiveCosmosOperations.findById
com.microsoft.azure.spring.data.cosmosdb.core.ReactiveCosmosTemplate.findById
com.microsoft.azure.spring.data.cosmosdb.repository.ReactiveCosmosRepository.findById
com.microsoft.azure.spring.data.cosmosdb.repository.ReactiveCosmosRepository.findAll
com.microsoft.azure.spring.data.cosmosdb.repository.ReactiveCosmosRepository.count
com.microsoft.azure.spring.data.cosmosdb.repository.ReactiveCosmosRepository.findAllById
com.microsoft.azure.spring.data.cosmosdb.repository.ReactiveCosmosRepository.existsById
Delete org.springframework.data.repository.CrudRepository.delete
org.springframework.data.repository.CrudRepository.deleteById
org.springframework.data.repository.CrudRepository.deleteAllById
org.springframework.data.repository.CrudRepository.deleteAll
org.springframework.data.repository.reactive.ReactiveCrudRepository.delete
org.springframework.data.repository.reactive.ReactiveCrudRepository.deleteAll
org.springframework.data.repository.reactive.ReactiveCrudRepository.deleteAllById
org.springframework.data.repository.reactive.ReactiveCrudRepository.deleteById
com.azure.spring.data.cosmos.repository.CosmosRepository.deleteById
com.azure.spring.data.cosmos.repository.CosmosRepository.delete
com.azure.spring.data.cosmos.repository.CosmosRepository.deleteAll
com.azure.spring.data.cosmos.repository.ReactiveCosmosRepository.deletebyId
com.azure.spring.data.cosmos.repository.ReactiveCosmosRepository.deleteAll
com.azure.spring.data.cosmos.repository.ReactiveCosmosRepository.delete
com.microsoft.azure.spring.data.cosmosdb.core.CosmosOperations.deleteAll
com.microsoft.azure.spring.data.cosmosdb.core.CosmosOperations.delete
com.microsoft.azure.spring.data.cosmosdb.core.CosmosOperations.deleteCollection
com.microsoft.azure.spring.data.cosmosdb.core.ReactiveCosmosOperations.deleteAll
com.microsoft.azure.spring.data.cosmosdb.core.ReactiveCosmosOperations.delete
com.microsoft.azure.spring.data.cosmosdb.core.ReactiveCosmosOperations.deleteCollection
com.microsoft.azure.spring.data.cosmosdb.repository.ReactiveCosmosRepository.deleteById
com.microsoft.azure.spring.data.cosmosdb.repository.ReactiveCosmosRepository.deleteAll
com.microsoft.azure.spring.data.cosmosdb.repository.ReactiveCosmosRepository.delete
com.microsoft.azure.spring.data.cosmosdb.repository.CosmosRepository.deleteById
com.microsoft.azure.spring.data.cosmosdb.repository.DocumentDbRepository.deletebyId
com.microsoft.azure.spring.data.cosmosdb.repository.DocumentDbRepository.deleteAll
com.microsoft.azure.spring.data.cosmosdb.repository.DocumentDbRepository.delete

Above mentioned methods are supported for both Synchronous and Asynchronous clients.

Objects

Icon Description
Java CosmosDB Database
Java CosmosDB Collection
Java Unknown CosmosDB Database
Java Unknown CosmosDB Collection
Link type Source and destination of link Methods Supported
parentLink Between CosmosDB Database object and CosmosDB Collection -
useInsertLink Between the caller Java Method objects and CosmosDB Collection save
saveAll
useSelectLink Between the caller Java Method objects and CosmosDB Collection existsById
findById
findAll
findAllById
count
useDeleteLink Between the caller Java Method objects and CosmosDB Collection delete
deleteAll
deleteById
deleteAllById

What results can you expect?

Some example scenarios are shown below:

CosmosDB Database Connection from Properties File

application.properties

application.properties

azure.cosmosdb.uri=https://cosmoswithspring.documents.azure.com:443/
azure.cosmosdb.key=2VanbwRYNeJKCUjb5StsnBKaatDcKGRUckHnlSUVSJXifWL3exjwjP2o6rJpt8fY24MRmtnctzcE8hWAlBsRZw==
azure.cosmosdb.database=cosmoswithspring

Cosmos DB Client Creation

@Configuration
@EnableDocumentDbRepositories
public class AppConfig extends AbstractDocumentDbConfiguration {
 
    @Value("${azure.documentdb.uri}")
    private String uri;
 
    @Value("${azure.documentdb.key}")
    private String key;
 
    @Value("${azure.documentdb.database}")
    private String dbName;
 
    public DocumentClient documentClient() {
        return new DocumentClient(uri, key, ConnectionPolicy.GetDefault(), ConsistencyLevel.Session);
    }
 
    public String getDatabase() {
        return dbName;
    }
}

Select Operation

CreateDocument

   @Autowired
    private AlertRepository alertRepository;

    @GetMapping("/all")
    public Iterable getAllAlerts() {
        if (StreamSupport.stream(alertRepository.findAll().spliterator(), false).count() > 0) {
            return alertRepository.findAll();
        } else {
            throw new ValidationException("No records found.");
        }
    }

 @GetMapping("/count")
    public long countAlert() {
        if (StreamSupport.stream(alertRepository.findAll().spliterator(), false).count() > 0) {
            return alertRepository.count();
        } else {
            throw new ValidationException("No records found.");
        }
    }

Insert Operation

QueryDocuments

 @PostMapping("/add")
    public StatusMessage addAlert(@Valid @RequestBody Alert alert) {
        Alert returnedAlert = alertRepository.save(alert);
        if (returnedAlert.getAlertId().isEmpty()) {
            throw new ValidationException("Error accessing Cosmos database.");
        }
        return new StatusMessage("200", "Alert Added");
    }

Delete Operation

DeleteDocument

@GetMapping("/deleteall")
    public StatusMessage deleteAllAlert() {
        alertRepository.deleteAll();
        
        return new StatusMessage("200", "Alert Deleted");
    }

 @DeleteMapping("/delete/{id}")
    public StatusMessage deleteAlert(@PathVariable String id) throws NotFoundException {
        //Optional<Alert> returnedAlert = alertRepository.findById(id);
        if (!alertRepository.existsById(id)) {
            throw new NotFoundException("No alert found with id: " + id);
        }
        alertRepository.deleteById(id);
        return new StatusMessage("200", "alert deleted.");
    }

Query Method Support

Repo with query method

@Repository
public interface AlertRepository extends CosmosRepository<Alert, String> {
// repo for alert
    List<Alert> findById(String priority);
}

Controller

@GetMapping("find/{id}")
    public Alert findAlert(@PathVariable String id) throws NotFoundException {
        return alertRepository.findById(id).orElseThrow(
                () -> new NotFoundException("No alert found with id: " + id)
        );
}

Query Methods with @Query annotation

Repository with @query methods

@Repository
public interface AddressRepository extends CosmosRepository<Address, String> {
    void deleteByPostalCodeAndCity(String postalCode, String city);

    void deleteByCity(String city);

    Iterable<Address> findByPostalCodeAndCity(String postalCode, String city);

    Iterable<Address> findByCity(String city);

    Iterable<Address> findByCityIn(List<String> cities);

    Iterable<Address> findByPostalCode(String postalCode);

    Iterable<Address> findByPostalCodeInAndCity(List<String> postalCodes, String city);

    Iterable<Address> findByStreetOrCity(String street, String city);

    @Query("select * from a where a.city = @city")
    List<Address> annotatedFindListByCity(@Param("city") String city);

    @Query("select * from a where a.city = @city")
    Page<Address> annotatedFindByCity(@Param("city") String city, Pageable pageable);
}
public void testAnnotatedQuery() {
        addressRepository.saveAll(Arrays.asList(Address.TEST_ADDRESS1_PARTITION1, Address.TEST_ADDRESS1_PARTITION2));

        final List<Address> result = addressRepository.annotatedFindListByCity(Address.TEST_ADDRESS1_PARTITION1.getCity());
        assertThat(result).isNotNull();
        assertThat(result.size()).isEqualTo(1);
        assertThat(result.get(0)).isEqualTo(Address.TEST_ADDRESS1_PARTITION1);
    }

Asynchronous API

All corresponding methods are represented and results are very similar to its Synchronous counterpart. Async Client creation:

import com.microsoft.azure.spring.data.cosmosdb.repository.ReactiveCosmosRepository;

import info.hayslip.AlertHoarder.models.Alert;
import org.springframework.stereotype.Repository;

@Repository
public interface AlertReactRepository extends ReactiveCosmosRepository<Alert, String> {
// repo for alert
}

Known Limitations

  • Database/Collection is created as unknown, if the name is not retrieved from the properties file or if the name could not be resolved.