2016 年 7 月

第 31 卷,第 7 期

本文章是由機器翻譯。

資料點 - 新的 Azure DocumentDB Node.js SDK

Julie Lerman

Julie Lerman過去幾年我已經開發採用 Aurelia 前端針對其資料存放區撰寫 Node.js 和 Azure DocumentDB 中的伺服器端 API 的範例應用程式。除了使用 Node.js 的伺服器端 API,我的應用程式也會利用 Azure documentdb Node.js SDK。而是比說明的完整應用程式,我將指向舊版的文件從 11 月 (msdn.com/magazine/mt620011) 與 2015 年 12 月 (msdn.com/magazine/mt595750) 當我寫了有關此應用程式。您甚至可以下載原始的應用程式,並比較這篇文章所述的變更會反映新來源。因為我經常要調整應用程式,您永遠可以看看在 GitHub 儲存機制和 bit.ly/25crZAG

由於變更 Aurelia、 的許多我使用 Node.js 套件、 DocumentDB 功能及甚至到上述的 SDK,在過去幾個月,進行一些更新,而不只是封裝,但也可以更新我的程式碼利用在較新功能的時候了。我將不會討論更新 Aurelia相反地,我也要我把重點放在 DocumentDB 中的變更和修改我 Node.js API 的程式碼受益於這些變更。

第 1 步: 實作非同步呼叫的承諾

我第一件事我 Node.js 專案上執行 「 npm 更新 」。更新順利,但較不成功之後執行應用程式。我快速時發生錯誤,告訴我,我使用的回呼變得有問題。某個位置中的相依性深度,API 現在注重 JavaScript 承諾大於回呼。承諾 (類似於非同步/等候在.NET 中) 的架構有了一段時間,但花熟悉建立範例時,請使用回呼的路徑。現在我底部開始著手,並按住我一口氣承諾取代所有 Node.js api 回呼的時候了。不幸的是,這不是只需取代詞彙,但它需要變更程式碼的實際結構。在我 API 層,談到 documentdb Node.js SDK 直接 DocDBUtils 檔案中使用回呼。和我談到 (在 DocDBUtils) 公用程式和 sdk DocDBDao 類別中使用回呼。也就是使用公用程式進行通訊時我有回呼的多層式的系統。最後,ninja.js 類別對 DocDBDao 類別的呼叫觸發程序的資料擷取或更新。這些方法也會使用回呼,而且相依於較低的檔案的回撥。因此,我需要實作承諾底部 (DocDBUtils) 組成。

有數種幫助承諾實作的 JavaScript Api。問︰ 和 DocumentDB 小組會使用 Q,因此使用承諾,針對 DocumentDB 進行編碼更簡單的工作時,其 Node.js sdk 建立包裝函式呼叫其中一個。這個包裝函式,documentdb q 承諾,是 GitHub 上的 bit.ly/1pWYHCE

因此,我的第一個步驟是安裝 Q 使用節點封裝管理員 (npm):

npm install documentdb-q-promises

然後,在所有已使用基底 SDK (上述的類別,以及一個稱為的 api.js) 的節點類別我必須修改原先讓我知道要使用從初始 SDK DocumentClient 類別的類別的 「 需要 」 陳述式︰

var DocumentDBClient = require('documentdb').DocumentClient;

為指向新的 API DocumentClientWrapper 類別︰

var DocumentDBClient = require('documentdb-q-promises').DocumentClientWrapper;

DocDbUtils 類別直接需要的額外 Q 程式庫參考,因此它的 DocumentDBClient 定義為︰

var DocumentClient = require('documentdb-q-promises').DocumentClientWrapper
  , Q = require("q");

接下來,我必須重整回呼程式碼使用的功能之一。我盡力與這一段時間直到我模式關閉為止。然後,您也可以使用 DocDBUtils 類別中的某些工作函式,就能更輕鬆地修正呼叫這個類別的類別中的函式。但我到達此點之前,它肯定的艱辛過程︰ 變更程式碼、 偵錯、 讀取錯誤、 其他可用一時 Google 和一次變更的程式碼。讓我的朋友保留我從太多影響我的頭時發生一些,griping Twitter 上。這不是這麼困難,因為,但只是因為 — 不論我的程式設計經驗,我仍然是菜鳥在 JavaScript 中的項目。

例如,我一開始使用 API 執行時,會叫用第一個函數︰ DocDbDao.js 的 init 方法。這個方法可確保 API 的其餘部分所知的 DocumentDB 帳戶、 連接到使用的驗證金鑰和知道資料庫的名稱,如所示 [圖 1

[圖 1 原始 getOrCreateDatabase 方法使用回撥

getOrCreateDatabase: function (client, databaseId, callback) {
  var querySpec = { *query for database name defined here* };
  client.queryDatabases(querySpec).toArray(function (err, results) {
    if (err) {
        callback(err);
    } else {
      if (results.length === 0) {
          var databaseSpec = {
            id: databaseId
          };
          client.createDatabase(databaseSpec, function (err, created) {
            callback(null, created);
          });
      } else {
        callback(null, results[0]);
      }
    }
  });
},

getOrCreateDatabase 會從 docDbDao 類別中的初始化函式呼叫。名為用戶端的參數是從原始 SDK DocumentDBClient 的執行個體。  第三個參數,名為回呼,是指呼叫的函式,在此情況下初始化。GetOrCreateDatabase 方法 querySpec 變數中定義的查詢,然後再呼叫 client.queryDatabase 查詢。如果 queryDatabase 傳回錯誤,getOrCreateDatabase 會透過回呼傳遞回呼叫的函式,該錯誤。否則系統會檢查結果。如果 results.length 為 0,它會建立新的資料庫,並接著會將資訊透過 createDatabase 傳回到呼叫函式傳遞。如果 results.length 不是 0,結果陣列中的第一個項目會傳回在回呼中傳回。

現在讓我們看看這個相同函式,所示 [圖 2, 、 重寫使用 (請記住,這些就像非同步/等候 Microsoft.NET Framework 中) 的承諾,利用提供 Q 的承諾實作。

[圖 2 getOrCreateDatabase 使用承諾

getOrCreateDatabase: function (client, databaseId) {
  var querySpec = { *query for database name defined here* };
    return client.queryDatabases(querySpec).toArrayAsync().then(function (results) {
      if (results.length === 0) {
          var databaseSpec = {
              id: databaseId
        };
        client.createDatabaseAsync(databaseSpec)
          .then(function (databaseResponse) {
            db = databaseResponse.resource;
            return client.createCollectionAsync(db._self, collectionDefinition);
          })
      }
      return results.feed[0];
  },
      function (err) { return err; }
  );
}

請注意第一件事是函式參數清單中沒有任何回呼。定義查詢之後, 函式呼叫 queryDatabases,但不是喜歡之前。此時,我使用 queryDatabases 包裝函式定義新的 sdk。而不是呼叫 toArray 上 queryDatabases,我使用 toArrayAsync 方法,也就是其中一個 documentdb-q-承諾 SDK 所提供的非同步方法的數字。toArrayAsync 傳回 Q 程式庫; 所定義的承諾類型的執行個體承諾具有"then"方法 (類似於等候您可能熟悉.NET Framework),可讓您定義 queryDatabases.toArrayAsync 呼叫完成時執行的函式。第一個的位元的邏輯表示該怎麼辦呼叫會成功。就像之前,我檢查看看是否長度為 0,表示資料庫尚不存在。如果這種情況,然後建立新的資料庫,但的 createDatabaseAsync 方法,這次,就像其他非同步方法一樣傳回承諾物件。如果已成功建立資料庫時,我接著會處理資料庫的回應。我省略了一些額外的邏輯周圍建立資料庫,但您可以看到它如果您下載範例程式碼。

此方法的下一個部分指定應該發生的事情如果查詢可找出資料庫,也就是只在結果中傳回第一個項目。ToArrayAsync 結果包含摘要的屬性包裝結果,這就是為什麼您會看到語法為 results.feed[0]。

最後,如果 queryDatabases 呼叫失敗,此函數會傳回錯誤。

現在您已逐步解說這,我們來看看模式一次︰

CallToAsyncFuction().then(function to execute when complete){
                          success logic
                          },
                          function(err) {failure logic}
                          );

您呼叫其中一個非同步方法,並使用其然後方法定義無名稱的函式呼叫完成時執行。在函式的邏輯中,您先指定程式碼,以執行方法都順利完成 (選擇性地傳回部分結果),然後如果方法失敗 (也使用傳回結果的選項) 執行的程式碼。

我已經實作修訂過的 API,取代所有的三個模型中的回呼建構在此模式。

不過,我不能只是現在偵錯,並預期此工作,因為我已經開始忍類別,這還不知道新的 documentdb-q-承諾 SDK 的功能之一的瀑布。您可以嘗試取代原始範例中的這些其他回呼,或請參閱下載中完全更新的方案。

現在 DocumentDB 我 Node.js 互動使用建議的技術,因此讓我們看看在 DocumentDB 中的一些其他功能,以及要探討的實作這些 API 中。

參數化的查詢

在我的範例中的第一個反覆項目,我會在我的.NET 應用程式中將永遠不會執行 ninja.js 類別中的項目 — 我寫了與字串串連的查詢字串。至少使用 ES6 啟用字串插補來執行該串連,但我仍是有點沒什麼好丟臉,且有自己找藉口。除了兩部。首先,我所提供的範例學習及尚未使用我的大腦。(嗎? 這個偶數計數) 第二個是問題的安全性不當時最重要的一點,因為執行 SQL Azure DocumentDB 上不是問題的太大,因為查詢的方式使用資料庫。即使說明文件指出,DocumentDB 不是真的容易受到資料隱碼攻擊的最常見的類型並非永遠是 evildoer 尋找能夠充分利用資料隱碼攻擊的機會。不過,最好都是額外的安全性,而參數化的查詢已進行資料存取是建議的作法很長的時間。

在舊版的範例中,篩選函式會定義一個名為 querySpec 具名查詢的內容類型。查詢屬性值是 SQL 中,用來擷取從 DocumentDB 忍一組︰

var querySpec = {
  query:
  'SELECT ninja.id, ninja.Name,ninja.ServedInOniwaban,ninja.DateOfBirth
  FROM ninja'
}

Filter 函式會讀取包含在 URL 中的篩選值。例如,當使用者搜尋的每個忍者,其名稱中包含 「 San 」,URL 是 localhost:9000/api/忍? q = San。原始函式會建構查詢述詞只是串連 request.query.q,述詞中找到的篩選值︰

q = ' WHERE CONTAINS(ninja.Name,"' + request.query.q + '")';

我則會附加至基底的查詢中,會儲存在 querySpec.query 的述詞。

即使資料隱碼攻擊不幾乎是以容易使用的篩選值,我已取代該位元邏輯的參數,將會了解 DocumentDB。而不是輸入的使用者 (San) 的篩選值串連起來,我會使用稱為 @namepart 述詞中的參數預留位置。然後我將新屬性加入至 querySpec 稱為參數,以 JSON 格式,其使用 DocumentDB 將會尋找的名稱和值的屬性定義。然後我就可以指定參數名稱和 URL 所傳入的查詢值︰

querySpec.query += " WHERE CONTAINS(ninja.Name, @namepart)";
  querySpec.parameters = [{
    name: '@namepart',
    value: request.query.q
}]

DocumentDB 便會執行這做為參數化查詢因此邪惡 SQL 無法損及我的資料。

告別自我連結,並不讓門叫用您的方式出

好,那就是有點惡劣,但多少人認為需要使用所有類型的物件,從 selfLinks 有關資料庫、 集合、 文件或其他 DocumentDB 中的物件是否。SelfLink 值是如何識別的物件本身在 DocumentDB 中。您必須查詢 DocumentDB 已知的識別項 — 資料庫或集合的名稱或文件的識別值,以取得其 selfLink,因此您無法執行其他操作。SelfLinks 都還在那裡,但是您不再需要它們與物件互動。如果您知道的詳細資料,以建立物件的連結,您可以使用,而不是 selfLink。我將示範,很快就在下一步的功能結合我則選擇採用的優點在我修改過的範例︰ Upserts。

更新插入以取代取代

我很想要在我的 API,我先從資料庫以擷取要更新的項目所需移除笨拙的更新函式︰

  1. 請確定它已存在
  2. 取得其 selfLink
  3. 取得完整的文件的存取,如果傳遞至 update 方法中的項目具有有限的結構描述

然後我必須更新用戶端應用程式傳遞至 update 方法的項目中的值從資料庫擷取的文件中的欄位。最後,我必須告訴 DocumentDB,以取代這個修改過的文件中的資料庫中現有的文件。您可以瀏覽舊版的文件或範例,看看 updateItem 函式中 docDbDao 如果您想知道此所有看起來像是。

幸運的是,在 10 月 Microsoft 宣布的不可部分完成的更新插入到 DocumentDB,讓它能夠找出給定的文件需要插入或更新的功能。請參閱相關的部落格文章, bit.ly/1G5wtpY 如需詳細的說明。

更新插入可讓我執行簡單的更新使用已開啟的文件。Documentdb-q-承諾 SDK 提供非同步版本的取代。以下是我的修訂的更新函式︰

updateItem: function (item) {
  var self = this;
  var docLink = "dbs/Ninjas/colls/Ninjas";
  item.DateModified = Date.now();
  return self.client.upsertDocumentAsync(docLink, item).then(function (replaced) {
    return replaced;
  },
    function (err) {
    return err;
    }
  );
},

請注意我要建置的 docLink 值。這是我提到幫助我避免需要從資料庫實際的 SelfLink 我想要更新文件的新功能。我只指定資料庫名稱是忍,集合也會發生命名為忍。我將 docLink 值隨著 upsertDocumentAsync 命令中,來自用戶端項目,然後將傳回的布林值 (取代),在執行命令時,會傳回。另外請注意,隨著非同步命令,我已經修改了此邏輯,利用非同步方法所傳回的承諾。您可以分辨因為我要再撰寫非同步方法。

還有更多已加入至 DocumentDB

雖然我一點的範例會利用只有少數的新功能,還有更多已加入至 DocumentDB 因為我撰寫了我先前的資料行。多個 SQL 命令會在那裡,包括分頁的頂端和 ORDER BY 排序。ORDER BY 依賴於索引上的集合,其意義,因為這是關於巨量資料,並且您需要調整以符合您特定需求的資料庫。此外,也可以修改現有的集合,而不需要面對不幸的先前選擇的索引編製原則。如果您使用 DocumentDB.NET 用戶端 API,LINQ 提供者已成為更豐富,您可以在閱讀有關 bit.ly/1Od3ia2

DocumentDB 是針對保存大量的資料,以及 Microsoft 正在努力簡化存取更有效率且更符合成本效益。為了這麼做,公司導入了資料分割索引鍵,可讓您將資料分割的集合,以配合 「 大量高比率或應用程式需要高輸送量、 低延遲存取資料的資料。 」 的 DocumentDB 的核心功能 閱讀更多有關資料分割索引鍵在 bit.ly/1TpOxFj

Microsoft 也會處理定價的問題,讓使用者無法建立其他集合,因為集合的數目與相關費用。新的計畫根據磁碟區的資料和輸送量,因此您可以使用更多的集合並不太擔心相當的集合,也沒有活動的成本過高。但仍有每個集合的輸送量最小值。小組會繼續尋找改善資源使用狀況,讓它們在未來可以降低這些最小值的方法。如需新的定價的詳細資訊,請瀏覽 bit.ly/1jgnbn9

DocumentDB 工具也有所變更,以及若要這樣做以後,它們會繼續。有多個方式可瀏覽 Azure 管理入口網站中,在 DocumentDB 和資料移轉工具已獲得更多功能。非常高興地看到,我是一項變更是 Visual Studio 的雲端總管擴充功能現在支援連接到和瀏覽 DocumentDB 的資料。您甚至可以編輯,並將變更儲存至雲端總管] 中,透過未經處理資料,但在此階段中,查詢不是可行。

若要跟上成長的功能集,敬請期待 DocumentDB 標記的部落格文章 Azure 部落格 (bit.ly/1Y5T1SB),並遵循 @documentdb Twitter 更新帳戶。


Julie Lerman 是 Microsoft MVP,.NET 指導和居住在佛蒙特山區的顧問。 您可以找到她針對資料存取和使用者群組和世界各地的研討會其他.NET 主題呈現。她的部落格網址 thedatafarm.com /blog 以及 Code First DbContext 版本,都可透過 O'Reilly Media 是 「 程式設計 Entity framework 」。在 Twitter 上追蹤她: @julielerman 並查看她 Pluralsight 課程 juliel.me/PS 影片

感謝以下的微軟技術專家對本文的審閱: Andrew Liu