go backarticles

Articles of SQLschool.gr Team

Cosmos DB Querying and Manipulate data

Antonios Chatzipavlis

Σε κάθε 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


Relative Articles

Leave your comment

Login with your SQLschool.gr account if you want to comment on this article.


PASS chapter logo

The Official PASS Local Group for Greece

1434 33 595 27 41 1330
sql school greece logo
© 2010-2019 All rights reserved