1

I am developing an application using Azure Cosmos DB for Spring.

I have a structure with model classes and a ReactiveCosmosRepository, which I use to do queries.

I normally annotate my queries in my repository class:

@Repository
public interface ArchivedDocumentRepository extends ReactiveCosmosRepository<ArchivedDocument, String> {

@Query("SELECT * FROM c)
Flux<ArchivedDocument> findAllArchivedDocuments();
    
@Query("SELECT * FROM c where c.document_id = @documentId")
Mono<ArchivedDocument> findArchivedDocument(@Param("documentId") String documentId);
    
}

But now I need to create the SQL using some logic, and cannot annotate it like this. How can I do this?

I have also used the Azure Cosmos SDK directly, where you do like this:

client = new CosmosClientBuilder().endpoint("SOMEURL")
        .key("SOMEKEY")
        .preferredRegions(Collections.singletonList("SOMELOCATION"))
        .consistencyLevel(ConsistencyLevel.EVENTUAL).buildClient();

database = client.getDatabase("DBNAME");
String containerName = "CONTAINERNAME";
CosmosContainer container = database.getContainer(containerName);

String sql = "SELECT * FROM c";

CosmosPagedIterable<DocumentMetadata> filteredDocumentMetadata = container.queryItems(sql, new CosmosQueryRequestOptions(), DocumentMetadata.class);

...
}

If I combine my existing repository code with similar code to this in my service, I can retrieve the data I like and build queries how I like, but it seems a bit unnecessary to e.g. instantiate "client" object, when I already have a connection?

Any advices? How can I combine both the SDK directly with the Spring layer to be able to create queries based on logic instead?

0

1 Answer 1

1

I think you are on right path. You probably need to work on lower level using CosmosAsyncClient

If you are using configuration which extends AbstractCosmosConfiguration then you dont even need to create CosmosAsyncClient since its defined in AbstractCosmosConfiguration class.

The custom repository

package com.vob.reactive.webflux.service;

import com.azure.cosmos.CosmosAsyncClient;
import com.azure.cosmos.models.SqlParameter;
import com.azure.cosmos.models.SqlQuerySpec;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

@Component
@Slf4j
public class CustomRepository {


    private final CosmosAsyncClient cosmosAsyncClient;

    @Autowired
    public CustomRepository(CosmosAsyncClient cosmosAsyncClient) {
        this.cosmosAsyncClient = cosmosAsyncClient;
    }

    public <T> Mono<T> getSomethingFrom(String database, String container, String id, Class<T> classType){
        return this.cosmosAsyncClient
                .getDatabase(database)
                .getContainer(container)
                .queryItems(new SqlQuerySpec("select * from c where c.document_id = @documentId", new SqlParameter("documentId", id)), classType)
                .single();
    }

}

You would probably need to improve getDatabase and getContainer by storing them in Map so you dont need to check if they exists each time

Sign up to request clarification or add additional context in comments.

6 Comments

But this approach also creates a new client? I already "have a client" created by the Spring Cosmos lib , so could I not reuse that somehow? In this case I will have two...
You can let me tune it
You right if you use cosmosdb config you dont even need to define AsyncClient bean its done in base class.
The structure worked fine! Was able to query database. But there was some error with how you sent parameter. It did not like @documentId in the query for some reason. But I can investigate that.
One more thing: You write "You would probably need to improve getDatabase and getContainer by storing them in Map so you dont need to check if they exists each time". Is there a resource/time penalty by calling getDatabase().getContainer()? The reference says that is gets the instances without doing a service call. Is it an issue to do these calls each time a query is sent?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.