uncategorized

使用Azure DocumentDB儲存資料

做Azure Notification Hub時候,雖然,查詢Notification Hub本身中PNS和註冊ID的對應表,但是,有時候會因為不明原因導致這份Mapping表消失,為了避免這現象,需要額外把這些資訊給額外儲存起來。在Azure除了能使用RMS DB存放資料外,也來試試看使用NoSQL來除儲存資料,選用DocumentDB作為這次的方案。

DocumentDB是屬於JSON資料庫且提供結構描述彈性,以及能依需求擴大和縮小資料庫,使用DocumentDB最重要是下面這樣的結構圖:

此外,DocumentDB本身也提供相對應各類型程式語言的API,所以,操作上就相對就方便許多

建立DocumentDB


要在Azure建立DocumentDB相當簡單,只需要到Azure Portal選用DocumentDB

並且填入相關設定值,就可以建立一個DocumentDB Account了

記住這時候只是建立DocumentDB Account,還沒有建立可以儲存的DB,換成RMS DB來說就只是建立好SQL Server還沒有建立SQL Server內的DB是一樣的,因此,還必須到DocumentDB Account中加入一個Database

這時候就會出現Database可以用了

DocumentDB的CRUD


一旦建立好Database後,後面就可以開始針對DocumentDB進行操作了,DocumentDB雖然是儲存資料,但是,其實把每一個Json資訊作為文件給儲存起來。例如你的Json格式如下:

1
{ "platform":"apns", "Handle":"cd", "Tags":['222','aaaa'] }

被放在DocumentDB中就是一筆資料,也可以說是一份文件,所以,你有多少份Json檔,就會有多少筆資料,而在DocumentDB為了存放這些『文件』,必須透過建立一個容器做儲存,因此,從DocumentDB AccountDocumentDBCollectionDocument,可以看出來其DocumentDB階層,如下圖

前面已經建立好了DocumentDB Database,還必須在DocumentDB Database中建立一個Collection儲存文件資料

其中,在DocumentDB的定價部分,則取決於Collection建置的規模大小了

在DocumentDB中除了你自行定義的資料欄位外,有一個預設會自動幫你加上的就是ID這個標籤,這個ID標籤可以讓系統幫你自動設定一組GUID碼,或是你自行設定自己想要的資訊,若是自行設定,前提必須確保ID是所有Document中的唯一值,若是你的Json檔中沒有ID欄位,系統也會自動幫你產生ID欄位

當Azure上面都設定好之後,現在就是可以下載.NET的DocumentDB SDK,到Nuget搜尋Microsoft.Azure.DocumentDB並安裝,就可以開始進行開發了,在開始前必須先到DocumentDB找到連線字串和金鑰

1
private string DocumentDBConnection = "Connection string"; private string DocumentDBKey = "Key";

Create

建立一份文件,首先必須先定義好此文件中的Json格式,換句話說也是欄位資訊

1
public class DeviceRegisterationInfo { [JsonProperty(PropertyName = "id")] public string Id { get; set; } public string PNS { get; set; } public string Platform { get; set; } public string Tags { get; set; } }

如上述所有說,如果沒有id欄位,系統會自動幫你設定,不過,如果對業務流程清晰的話,我還是建議自己設定會比較好,至少在搜尋時候可以依照ID進行搜尋會比較快。開始建立與DocumentDB的連線

1
2
3
private DocumentClient client;
private void DBconnection() { this.client = new DocumentClient(new Uri(DocumentDBConnection), DocumentDBKey); }

Collection內有該份ID文件時,你並不能再建立一個相同ID文件去覆蓋掉它,如果你要強行建立就會發生DocumentClientException

Message: {“Errors”:[“Resource with specified id or name already exists”]}
ActivityId: 1b1a3770-e220-4bd5-b8dc-5bf48a8042bb, Request URI: /apps/cd04a067-b8de-46a2-8825-a25652296b7f/services/7af737f3-15ed-4ae9-98bb-08865fe0fbb5/partitions/dec123e2-d08a-4f2e-88d8-311e6a8e2e0e/replicas/131139654072259410p

不過,當你要去查這筆文件時候,如果也查不到文件時候,也會發生DocumentClientException錯誤,這時候就可以去建立一筆新的文件資料

1
2
private async Task Insertdata(string databaseName, string collectionName, DeviceRegisterationInfo inDocument) { try { await this.client.ReadDocumentAsync(UriFactory.CreateDocumentUri(databaseName, collectionName, inDocument.Id)); } catch (DocumentClientException ex) { if (ex.StatusCode == HttpStatusCode.NotFound) { await this.client.CreateDocumentAsync( UriFactory.CreateDocumentCollectionUri(databaseName, collectionName), inDocument); } }
}

就可以執行寫入資料的程式了

1
Program p = new Program(); p.DBconnection(); DeviceRegisterationInfo dr = new DeviceRegisterationInfo(); dr.PNS = "test1"; dr.Platform = "APNS"; dr.Tags = "Azure"; dr.Id = "edwardkuo3@gmail.com"; p.Insertdata("test", "demo1",dr);

結果如下,資料中的ID,會等同Azure管理介面上的『識別碼』

Read

要讀取資料很簡單,就是透過Linq語法和DocumentDB溝通就可以

1
IQueryable<DeviceRegisterationInfo> result = this.client.CreateDocumentQuery<DeviceRegisterationInfo>( UriFactory.CreateDocumentCollectionUri(databaseName, collectionName)) ; foreach (DeviceRegisterationInfo family in result) { Console.WriteLine("ID {0}", family.Id); Console.WriteLine("Tag {0}", family.Tags); }

就可以取出來了

Update

要更新資料,基本上你必須知道你要更新文件的ID,才有辦法直接更新資料,所以,一開始是使用系統幫你設定的ID編碼,就必須先查出文件ID才有辦法進行更新資料

1
2
private void Updatedata(string databaseName, string collectionName, DeviceRegisterationInfo inDocument) {
this.client.ReplaceDocumentAsync(UriFactory.CreateDocumentUri(databaseName, collectionName, inDocument.Id), inDocument); }

目前資料如下,要把edwardkuo3@gmail.com中的PNS值改為WPSTag值改成Azure

修改DeviceRegisterationInfo內容

1
DeviceRegisterationInfo dr = new DeviceRegisterationInfo(); dr.PNS = "test1"; dr.Platform = "WPS"; dr.Tags = "Azure"; dr.Id = "edwardkuo3@gmail.com";

結果如下

Delete

刪掉資料,就只需要把ID放入就可以輕鬆刪除資料

1
this.client.DeleteDocumentAsync(UriFactory.CreateDocumentUri(databaseName, collectionName, inDocumentD.Id))


在操作DocumentDB中的Database Name和Collection名稱記得要注意大小寫,在Function中的大小寫與Azure上的設定不同,會不Work的