2

I'm trying to partition a collection based on a nested Java object and the corresponding Json. I know it might seem unreasonable to do this, but I am working on a project far into development, and the layout expected by our client team is not flexible at the moment. Ex.) The equivalent Json for an object called receiptItem looks like this:

{
   "id": "1",
   "item": { 
      "itemId": "1",
      "name": "itemName",
      "value": 4.98,
      ...
   }, 
   "tax": {
      "rate": 0.15,
      "state": "FL",
      ...
   },
   ...
}

Is it possible to create a partition key in Azure with a syntax along the lines of "/item.itemId"? Any other way to go about this while utilizing itemId as the partition key for the receiptItem collection?

If there is an answer for how to do this in Azure, I would also be interested in figuring out what the corresponding Java code would look like. Unlike C#, the @PartitionKey annotation does not seem to have an attribute to specify a nested object, (as in [ParitionKey(item.id)]), and I do not see a way to do this in my configurations (in Spring boot) either.

In Java, would look like:

@Data
@NoArgsConstructor
@FullArgsContructor
@ToString
@Document(collection="receiptItems")
public class ReceiptItem {
   @Id
   int id;
   // @PartitionKey???
   Item item;
   Tax tax;
   ...
}
7
  • 1
    You cannot use an item in an array as part of partition key. I'd recommend just creating a new property on your object called "partitionKey" and setting it with your desired value. The downside is that you've duplicated your data, but you can keep your schema the way it is. Commented Mar 14, 2019 at 20:17
  • Ok, I was afraid that would be the case. Thanks for the comment. Commented Mar 14, 2019 at 20:19
  • 1
    On second thought, I'm not sure why I even have brackets at all since the class in my actual code is not a collection. I will edit the question and and continue to wait for answer with that in mind. Commented Mar 14, 2019 at 20:24
  • 1
    I'm gonna follow up on how to do this with the Spring Data connector. We should get a sample published for this. You can achieve it by creating the collection from the portal/emulator UI by setting the partition key path to "/item/itemId", but I am unsure if that will "just work" with Spring. I'll get the Spring folks to give us an answer. Commented Mar 14, 2019 at 22:30
  • 1
    Looks like it is not yet supported in Spring to declare the partition key on a subobject, so you'll have to precreate it via cli/portal/sql sdk for now to use a nested type. I've created an issue to help track: github.com/Microsoft/spring-data-cosmosdb/issues/350 Commented Mar 15, 2019 at 21:35

2 Answers 2

2

I am stuck with a similar issue and I had to move out my partition key from the nest. Even after that, I could not find any way to let my MongoRepository in spring boot know about the partition key. I have raised the issue here - Spring Boot not able to update sharded collection on azure cosmos db(MongoDb)

As normal insertion and fetching would work fine as long as you have partition key present in your object. It is the Update and Delete queries which would fail.

I came up with a workaround. I had to Autowire MongoTemplate and Create a basic Query to update my object.

public DocumentDev updateProcessedFlag(DocumentDev request) {
    Query query = new Query();
    query.addCriteria(Criteria.where("_id").is(request.getId()));
    // dNumber is my partition key here.
    query.addCriteria(Criteria.where("dNumber").is(request.getDNumber()));
    Update update = new Update();
    update.set("processed", request.isProcessed());
    mongoTemplate.updateFirst(query, update, request.getClass());
    return request;
}

Another variation to this can be using udate.fromDocument(Document,Exclude) function where you might need to convert your object into BSON document and use it like this.

public DocumentDev updateProcessedFlag(DocumentDev request) {
    // convert your object to document
    Gson gson = new GsonBuilder().create();
    String json = gson.toJson(pojo);
    Document doc = Document.parse(json);

    // create query
    Query query = new Query();
    query.addCriteria(Criteria.where("_id").is(request.getId()));
    query.addCriteria(Criteria.where("dNumber").is(request.getDNumber()));
    Update update = Update.fromDocument(doc,"");
    // run update command using mongoTemplate
    mongoTemplate.updateFirst(query, update, request.getClass());
    return request;
}

If there is any way to tell spring boot about partition key. That would be a better solution. Until then this is the workaround I came up with.

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

1 Comment

As of now I am able to do all basic CRUD/DocumentDbRepository ops. The problem is that I am not utilizing the partition key that would be ideal for my data, which is of growing concern as the num of users/requests is increasing. Thanks for your answer though.
-1

For now it is certainly possible to have a 'nested' partition key in Azure. For example, /item/id would be used to make the id field in item the partition key. The corresponding Json doc would look like this:

{
   "id": "1",
   "item": { 
      "itemId": "1",
      "name": "itemName",
      "value": 4.98,
      ...
   }, 
   "tax": {
      "rate": 0.15,
      "state": "FL",
      ...
   },
   ...
}

Unfortunately, nested partition keys are not currently supported in Spring. Thanks very much to ChrisAnderson-MSFT for getting involved in looking for a solution, and for opening up the issue on github, which can be found here: https://github.com/Microsoft/spring-data-cosmosdb/issues/350.

Comments

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.