Cosmos DB read a single document without partition key
Asked Answered
C

2

6

A container has a function called ReadItemAsync. The problem is I do not have the partition key, but only the id of the document. What is the best approach to get just a single item then?

Do I have to get it from a collection? Like:

var allItemsQuery = VesselContainer.GetItemQueryIterator<CoachVessel>("SELECT * FROM c where c.id=....");

var q = VesselContainer.GetItemLinqQueryable<CoachVessel>();
var iterator = q.ToFeedIterator();

var result = new List<CoachVessel>();
while (iterator.HasMoreResults)
{
    foreach (var item in await iterator.ReadNextAsync())
    {
        result.Add(item);
    }
}
Crashaw answered 9/7, 2020 at 15:37 Comment(2)
Yes you have to do a fan out query but id is only distinct per partition key so even then you may end up with multiple items. Frankly speaking, if you don't have the partition key for a point read then the model for the database is not correct. It should be redesigned.Boletus
Unfortunately data is coming from an external API and I cannot ask them to redesign. But thanks for your reply. Can you create an answer that states it is not possible to do it without partition key.Crashaw
B
9

Posting as answer.

Yes you have to do a fan out query but id is only distinct per partition key so even then you may end up with multiple items. Frankly speaking, if you don't have the partition key for a point read then the model for the database is not correct. It (or the application itself) should be redesigned.

Additionally. For small, single partition collections this x-partition query will not be too expensive as the collection is small. However, once the database starts to scale out this will get increasingly slower and more expensive as the query will fan out to ever increasing numbers of physical partitions. As stated above, I would strongly recommend you modify the app to pass the partition key value in the request. This will allow you to do a single point read operation which is extremely fast and efficient.

Good luck.

Boletus answered 9/7, 2020 at 20:53 Comment(3)
I didn't realise passing the partition key in the request would be a good practice, but I am still unsure about picking a partition key. When you want to retrieve a single item in a collection, how could you possibly always know the partition key?Ferrosilicon
The partition key should ideally be innate to the data itself. For instance, when looking up a customer, you ideally would use some piece of data that is associated with the customer. Maybe it's a phone number, maybe its something else. If you're new to modeling data for this type of database I definitely recommend reading this article. Most people get an "aha" moment when they read it. learn.microsoft.com/en-us/azure/cosmos-db/…Boletus
@MarkBrown thanks for the link, really good one. It teaches to don't be afraid of the denormalization and it's "ugliness" (and it is VERY ugly, as for me).Treharne
P
1

Try using ReadItemAsync like:

dynamic log = await container.ReadItemAsync<dynamic>(ID, PartitionKey.None);
Paisano answered 7/7, 2022 at 21:46 Comment(1)
This is not correct. If the field is defined (i.e. customer_name) and you have a value in it (i.e. BoA) then it will not perform a cross partition search. It will instead throw a not found error.Hypodermic

© 2022 - 2024 — McMap. All rights reserved.