Search code examples
c#azureazure-cosmosdbpartition

Current Code Cosmos DB 3.37.1: PartitionKey key mismatch exception


This question had been asked many times and even answered correctly a few times, I've seen them all, and yet, it happens to me no matter what I do. Here is the code:

Creating container:

string partitionKeyPath = $"/{_userId}";
_container = await database.CreateContainerIfNotExistsAsync(_containerName, partitionKeyPath);

Then when the time comes to add my Chat object:

if (_container != null)
{
    Chat? chat;
    bool newChatCreated = false;
    try
    {
        // Attempt to read the Chat item. If it exists, add the ChatItem to it.
        chat = await _container.ReadItemAsync<Chat>(chatId, new PartitionKey(_userId)).ConfigureAwait(false);
    }
    catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
    {
        // If the Chat item does not exist, create a new one.
        chat = new Chat
        {
            id = chatId,
            _userId = _userId,
            ChatItems = new List<ChatItem>(),
            ChatName = chatName,
            IndexName = indexName,
            TimeCreated = DateTime.Now.ToString("yyyy/MM/dd-HH:mm:ss.fff")
        };

        ContainerProperties props = await _container.ReadContainerAsync();
        _logger.LogInformation($"PartitionKeyPath: {props.PartitionKeyPath}");

// Exception happens on the next line in CreateItemAsync !!!
        await _container.CreateItemAsync<Chat>(chat, new PartitionKey(_userId));

        newChatCreated = true;
    }

    chat?.ChatItems?.Add(chatItem);

    if (newChatCreated)
    {
        // Update the Chat item in the database
        await _container.ReplaceItemAsync<Chat>(chat, chatId, new PartitionKey(_userId));
    }
    else
    {
        var patchOperations = new List<PatchOperation>
        {
            PatchOperation.Add("/ChatItems/-", chatItem)
        };
        await _container.PatchItemAsync<Chat>(chatId, new PartitionKey(_userId), patchOperations);
    }
}
else
{
    _logger.LogError("_container is null");
    return false;
}

The _userId that serves as the PartitionKey is all alphanumeric small case: "supportgpt4officecom". The PartionKeyPath is the same but prepended with '/', that is: "/supportgpt4officecom" (verified by logging it just before the call.)

So, is anybody can explain to me what's going on? BTW, I am running the latest CosmosDB version: Microsoft.Azure.CosmosDB 3.37.1


Solution

  • string partitionKeyPath = $"/{_userId}";
    

    The Container's Partition Key Definition should have the name of the property and its path, not the value.

    For example, let's say your Document has the _userId property, then it should be:

    string partitionKeyPath = "/_userId";
    

    When you do the item operations, you then, as you are doing correctly, pass the Partition Key Value which is, the value of the _userId property for that Document.

    If the property name is not _userId just alter the code for the correct property name.