sqlschool.gr logo

articles

Articles of SQLschool.gr Team

Cosmos DB Querying and Manipulate data

Antonios Chatzipavlis
Wednesday 09 January 2019

Σε κάθε database το βασικό και πρακτικό ερώτημα είναι το πως διαβάζω και επεξεργάζομαι δεδομένα και αυτά παρουσιάζονται στο άρθρο αυτό.

Retrieving Data

Το πρώτο που ζητάει κάποιος από μια βάση δεδομένων είναι να μάθει πως θα αντλεί στοιχεία από αυτή.

Στην Cosmos DB υπάρχουν τρεις διαφορετικοί τρόποι να κάνουμε αυτό είναι με SQL, LINQ, Lambda.

Σε κάθε περίπτωση χρησιμοποιείται υπάρχουσα γνώση εφόσον φυσικά έχουμε ασχοληθεί με αυτά στο παρελθόν και αυτό βοηθάει ιδιαίτερα.

Δεν έχω την πρόθεση στο άρθρο αυτό να επαναλάβω ήδη υπάρχοντα πράγματα για αυτό σας προτείνω να δείτε το documentation που είναι εξαιρετικό και είναι στα παρακάτω links:

Αυτό που θέλω να τονίσω είναι ότι στις εφαρμογές μας μπορούμε να διαβάσουμε δεδομένα χρησιμοποιώντας διάφορες classes που υπάρχουν στο Microsoft.Azure.Documents.Client namespace.

Μια από τις βασικότερες class είναι η DocumentClient και μπορούμε να συνδεθούμε και να διαβάσουμε δεδομένα από την εφαρμογή μας όπως στα παρακάτω code examples

// Connect to Cosmos DB
string AccountKey = "<your account key>";
string EndpointURI = "https:// XXXXX.documents.azure.com:443";
client = new DocumentClient(new Uri(EndpointUrl), AccountKey);

// Simple query

var deviceQuery = this.client.CreateDocumentQuery<T>(myCollection, $"SELECT DISTINCT c.propname FROM c");
var deviceData = await Task.Run(() => deviceQuery.ToList());

// In-line result processing

string deviceQueryString = $"SELECT DISTINCT c.propname FROM {this.collection} c";
var deviceQuery = this.client.CreateDocumentQuery<T>(myCollection, $"SELECT DISTINCT c.propname FROM {this.collection} c").AsDocumentQuery();
while (deviceQuery.HasMoreResults)
{
var records = deviceQuery.ExecuteNextAsync().Result;
    foreach (var record in records)
    {
        Console.WriteLine($"{record}\n");
    }
}


// Using LINQ

string queryString = $"SELECT c.prop1, c.prop2, c.prop3 FROM T AS c";
SqlQuerySpec querySpec = new SqlQuerySpec()
{ 
    QueryText = queryString
};
var query = this.client.CreateDocumentQuery<T>(myCollection, querySpec).AsEnumerable();
var docs = from doc in query
           group doc by doc.prop1 into grp
           select new mydata
           {
               …
           };
var d = await Task.Run(() => docs.ToList());

Creating Documents

Μπορούμε να εισάγουμε νέα documents χρησιμοποιώντας την CreateDocumentAsync method της DocumentClient class αφού πρώτα έχουμε ένα POCO class serialized σε json για το document το οποίο το δίνουμε σαν URI στην αντίστοιχη παράμετρο της μεθόδου

MyPOCO p= new MyPOCO
{
    Prop1 = …,
    Prop2 = …,
    …
    PropN = …
};
Uri collectionUri = UriFactory.CreateDocumentCollectionUri(this.database, this.collection);
var response = await this.client.CreateDocumentAsync(collectionUri, p);

Deleting Documents

Με την DeleteDocumentAsync method της DocumentClient class διαγράφουμε documents όπως στο παρακάτω code sample

Console.WriteLine("Enter document ID");
string id = Console.ReadLine();
Uri docUri = UriFactory.CreateDocumentUri(this.database, this.collection, id);
var response = await this.client.DeleteDocumentAsync(docUri);

Modifying documents

Με την ReplaceDocumentAsync method της DocumentClient class κάνουμε αλλαγές στο documents όμως θα πρέπει να γνωρίζουμε δεν υπάρχει in-place update για αυτό θα πρέπει να διαβάσουμε όλο το document στον client να κάνουμε την αλλαγή σε αυτό και μετά να το κάνουμε όλο update στην βάση και εδώ πρέπει να λάβουμε σοβαρά το concurrency που θα επιλέξουμε ή έχουμε επιλέξει.

Η Cosmos DB έχει ETags τα οποία η κάθε εφαρμογή μπορεί να χρησιμοποιήσει ώστε να αποφευχθούν concurrency issues. Αυτό μπορεί να γίνει με την χρήση του AccessCondition object το οποίο το δίνω σαν request option στην ReplaceDocument Async για το ETag του document και αν στο replace αυτό έχει από αλλού αλλάξει τότε παίρνω λάθος όπως στο παρακάτω code sample.

Console.WriteLine("Enter document ID");
string id = Console.ReadLine();
Uri docUri = UriFactory.CreateDocumentUri(this.database, this.collection, id);
var documentResponse = await client.ReadDocumentAsync(docUri);
var doc = documentResponse.Resource;
Console.WriteLine(doc.ToString());
double T = doc.GetPropertyValue<double>("p");
doc.SetPropertyValue("p",  T + 1000);
RequestOptions options = new RequestOptions
{
    AccessCondition = new AccessCondition
    {
        Condition = doc.ETag,
        Type = AccessConditionType.IfMatch
    }
};
var response = await client.ReplaceDocumentAsync(doc.SelfLink, doc, options);

Error Handling during manipulations

Σε όλες τις παραπάνω διαδικασίες πρέπει πάντα στο τέλος να ελέγχω αν αυτές έχουν γίνει με επιτυχία ή όχι και για αυτό το λόγο όλα τα response object που δημιουργώ για αυτές επιστρέφουν την ResourceResponse class η οποία έχει το StatusCode property όπως στο code sample

Console.WriteLine($"Status code is {response.StatusCode}");

Όλες μπορείτε να τις επιστρεφόμενες τιμές μπορείτε να τις δείτε εδώ

Attachments

Όπως έχω αναφέρει σε παλαιότερο άρθρο μου αν έχω blobs ή document property που είναι πάνω από 2ΜΒ αποθηκεύω αυτό σαν document attachment.

Η DocumentClient class έχει τις εξής μεθόδους για κάνουμε κάτι τέτοιο

  • CreateAttachmentAsync - create an attachment.
  • DeleteAttachmentAsync - delete an attachment.
  • ReplaceAttachmentAsync - replace an attachment.
  • CreateAttachmentQuery - query the attachments associated with a document.
  • ReadMediaAsync - read an attachment by its Id.

Code Samples

// Add Attachemnt 
var response = await this.client.CreateDocumentAsync(collectionUri, doc);
//... Set up a stream to read the data to upload for the attachment
// Create the attachment
var attachmentResponse = await client.CreateAttachmentAsync(response.Resource.AttachmentsLink, stream,
    new MediaOptions
    {
        ContentType = "application/jpeg",
        Slug = Guid.NewGuid().ToString()
    });
 
// Querying Attachments
foreach (var attachment in client.CreateAttachmentQuery(doc.SelfLink))
{
    var data = await client.ReadMediaAsync(attachment.MediaLink);
StreamReader reader = new StreamReader(data.Media);
... Read the data for the attachment using the StreamReader
}



// Directly Read an Attachment
var attachLink = doc.AttachmentsLink + "{your attachmentid }/";
Attachment attachment = await client.ReadAttachmentAsync(attachLink);

//antonch

Antonios Chatzipavlis

Antonios Chatzipavlis

Antonios is a Data Solutions Consultant and Trainer. He has been working in IT since 1988. In his career, he has worked as senior developer, IT Manager, Solutions Architect and IT Consultant. Since 1995 he has been devoted on new technologies and software development tools, mainly by Microsoft, either by training company staff and colleagues or assisting them in design, development and implementation as a consultant or chief developer. He has focused in Databases and Data Science since 1995. He specialized in Microsoft SQL Server since version 6.0 in areas like SQL Server Internals, Database Design and Development, Business Intelligence and in 2010 he has started working with Azure Data Platform, NoSQL databases, Big Data Technologies and Machine Learning. He is an active member of many IT communities in Greece, answering colleagues' questions and writing articles in his web site. He is the owner of SQLschool.gr which is a community portal with a lot of information about Microsoft SQL Server. He has been a Microsoft Certified Trainer (MCT) since 2000. Microsoft honored him as MVP on Data Platform due to his activities in SQL Server since 2010. He holds a large number of Microsoft Certifications and Microsoft SQL Server Certifications since version 6.5.

Tip

What's New in SQL Server 2022 - Episodes

More Tips...

Become a member

If you want to receive updates from us become a member to our community.

Connect

Explore

Learn


sqlschool.gr © 2010-2024 All rights reserved

This site uses cookies for operational and analytics purposes only. By continuing to browse this site, you agree to their use.