CacheThings
CacheThing 提供快速的記憶體內介面,用於儲存及擷取金鑰值資料。該介面適用於快取昂貴或耗時操作 (例如慢查詢) 的結果。
由於 CacheThing 在記憶體中運作,因此,當 ThingWorx 重新啟動時,會清除其內容。在高可用性 (HA) 環境中,每個 ThingWorx 節點都會維護自己的獨立快取。因此,在一個節點上建立或更新的快取項目不會自動與其他節點共用。這包括快取失效呼叫,例如 PurgeCacheDeleteEntryDeleteEntryByKey
您可以使用 CacheThing 來快取各種類型的資料,包括:
昂貴或頻繁查詢資料庫物件的結果
昂貴或頻繁查詢 ValueStreams 或 DataTables 的結果
慢速網路呼叫的結果,例如使用 ContentLoaderFunctions 進行的呼叫
昂貴的計算值
FileRepositories 中常用的非常小檔案的內容
相較於存取外部系統 (例如資料庫或網路資源),使用 CacheThing 可以顯著改善效能並減少資源使用。
使用指南
CacheThing 並非作為永久資料存放區使用。在 CacheThing 中快取的任何資料都應該可從原始來源重現。
CacheThing 中的資料可能已到期或收回。使用 CacheThing 的服務應設計為在快取未傳回結果時,從原始來源擷取資料。如需詳細資訊,請參閱範例
組態
每個 CacheThing 都必須使用包括主索引鍵的 DataShape 配置。主索引鍵可用來從快取中擷取項目。
支援複合主索引鍵,但它們會阻止使用下面列出的 ByKey 便利服務到期原則和全域最大大小。
到期原則
「到期原則」定義每個快取項目的存留時間 (TTL)。您可以使用「快取項目到期時間 」設定來配置到期時間。項目到期之後,擷取值會傳回空白結果,這種情況與從快取中將其刪除類似。
支援的到期原則:
快取項目到期原則
描述
「從不」
系統從不根據快取項目在快取中花費的時間量來移除快取項目。但是,仍可在快取達到最大大小組態的情況下或使用 DeleteEntry 服務來收回。配置 Never 到期原則時,會略過「快取項目到期時間 」設定。
「自上次存取以來的到期時間」
如果在指定到期時間內未讀取項目,則會將其移除。
「自建立以來的到期時間」
建立後,項目會在經過指定時間後移除。
「自上次修改後的到期時間」
如果在指定到期時間內未修改項目,則會將其移除。
「自上次接觸後的到期時間」
如果在指定到期時間內未存取或修改項目,則會將其移除。
如需有關介面到期原則的詳細資訊,請參閱介面到期原則
「快取最大大小 (收回)」
當快取達到「快取最大大小 (MB)」設定中指定的大小時,會自動收回 (刪除) 快取項目。收回流程會移除最不常用 (LFU) 的項目,以便為新項目騰出空間。收回項目後,擷取項目會傳回空白結果,類似於將其刪除時的情況。
如果新增大型項目,可能會收回多個較小的項目以容納該項目。為避免發生這種情況,請使用 EstimateEntrySize 服務檢查項目的大小,然後再將其新增至快取。
快取收回和到期會獨立操作。
收回以快取大小和使用頻率為基礎。
到期以時間為基礎,如配置的到期原則所定義。
全域最大大小
「平台子系統」包括一個名為「每個 ThingWorx 節點在所有快取物件之間共用的最大大小 (MB)」的設定。此設定會限制單一節點上所有 CacheThings 的組合大小,以防止使用過多記憶體。已禁用的 CacheThings 不包括在此限制內。
此組態可防止執行下列動作:
建立超出最大大小的新 CacheThing
更新超過最大大小之 CacheThing 的「快取最大大小 (MB)」
匯入 CacheThings (作為實體匯入或延伸功能的一部份) 超過最大大小,導致整個匯入失敗
將最大大小減小到所有 CacheThings 的目前組合「快取最大大小 (MB)」之下
啟動超過全域限制的 CacheThing
變更快取組態
對快取組態的任何變更都將自動清除快取以維持內部一致性。編輯以下任何一項都將會清除快取:
「資料形式」- 包括修改已配置的資料形式,例如新增或移除欄位。
「快取項目到期原則」
「快取項目到期時間 」
「快取最大大小 (MB)」
「快取執行未命中項目的載入」
服務
下列服務可在 CacheThing 上找到。在高可用性 (HA) 環境中,這些服務會影響執行服務之 ThingWorx 節點中的快取。
以下列出的 *ByKey 便利服務只有在快取的資料形式具有單一主索引鍵時才可用。如果快取的資料形式包括多個主索引鍵,請使用完整資料負載輸入版本的服務。
服務名稱
描述
PutEntry
將項目新增至快取。
輸入值 - 使用 CacheThing 的已配置資料形式的一列資料負載。
GetEntry
從快取傳回一列資料負載結果。
如果找不到項目 (快取未命中),且未使用「快取執行未命中項目的載入」配置快取,則會傳回空資料負載。如果使用該選項配置快取,則會自動呼叫 LoadEntry 服務,並傳回其結果。
如果項目從未新增至快取、遭到收回或到期,則可能會發生快取未命中的情況。
輸入值 - 使用 CacheThing 的已配置資料形式的一列資料負載。只應填入 Primary Key 值。
GetEntryByKey
從快取傳回一列資料負載結果。
如果找不到項目,會傳回空資料負載。如果項目從未新增至快取、遭到收回或到期,則可能會發生快取未命中的情況。
輸入值 - 字串表示所擷取項目的主索引鍵。只有在資料形式具有單一主索引鍵時,此服務才可供使用。該服務最適合字串主索引鍵,但也支援具有明確字串轉換的大多數類型。
LoadEntry
用於在發生快取未命中時,自動從資料來源擷取快取資料。
如果啟用「快取執行未命中項目的載入」,則必須取代此服務。
DeleteEntry
從快取中刪除項目。
在高可用性環境中,這僅影響呼叫 DeleteEntry 服務的節點。
輸入值 - 使用 CacheThing 的已配置資料形式的一列資料負載。只應填入 Primary Key 值。
DeleteEntryByKey
從快取中刪除項目。
在高可用性環境中,這僅影響呼叫 DeleteEntryByKey 服務的節點。
輸入值 - 字串表示所擷取項目的主索引鍵。只有在資料形式具有單一主索引鍵時,此服務才可供使用。
PurgeCache
移除所有快取項目。
在高可用性環境中,這僅影響呼叫 PurgeCache 服務的節點。
GetDataShape
傳回快取的已配置資料形式。
SetDataShape
設定快取組態表中的「資料形式」欄位。變更此值將會自動清除快取。
GetEstimatedEntryCount
傳回快取中的預估項目數。正在進行的 PUT 和 DELETE 操作以及到期或收回流程可能會影響準確性。
EstimateEntrySize
如果項目已新增至快取,會傳回其預估大小。這樣並不會將項目放進快取中,也不需要在快取中已有任何項目。此服務可用於預估適當的「快取最大大小 (MB)」,或防止將大型項目新增至快取。
輸入值 - 使用 CacheThing 的已配置資料形式的一列資料負載。
取代 LoadEntry 服務
欲啟用「快取執行未命中項目的載入」(通讀快取),您必須在 CacheThing 上取代 LoadEntry 服務。當發生快取未命中時,會在內部呼叫此服務,以使快取能夠從來源擷取及儲存資料。
直接呼叫 LoadEntry 服務並不會將項目新增至快取。只有當 LoadEntry 在快取未命中期間從內部呼叫 GetEntry 時,才會新增項目。
「輸入」
輸入是符合對應 GetEntry 呼叫參數的單列資料負載。通常,只會填入主索引鍵欄位。
服務實行
LoadEntry 服務應擷取或產生要從資料來源快取的值。這可能包括資料庫查詢、Web 服務呼叫或產生的值。避免更新服務中的應用程式狀態,例如內容或檔案。
請勿從 LoadEntry 內呼叫其他快取服務,例如 GetEntryPutEntry。快取未命中後,快取會自動處理傳回值的儲存。
輸出
輸出必須是資料負載,其資料形式與輸入相同。將擷取的資料填入非主索引鍵欄位。任何例外都會傳播到呼叫 GetEntry 呼叫。
最佳作法是針對輸出結果資料負載建立新資料負載。雖然可以重複使用並填入輸入值資料負載,但由於資料負載在 Javascript 中處理某些基礎類型的方式受到限制,這樣做可能會導致發生意外行為。如需使用 LoadEntry 的詳細資訊,請參閱範例
通讀快取
選取「快取執行未命中項目的載入」核取方塊可啟用通讀快取。在此模式下,當發生快取未命中時,快取會使用 CacheThing 中的 LoadEntry 服務自動載入未命中項目值。
欲支援此行為,您必須取代 CacheThing 中的 LoadEntry 服務,以查詢來源資料並傳回適當值。當 GetEntry 服務在快取中找不到值時,快取會呼叫 LoadEntry 服務以擷取值。
通讀快取有助於緩解驚群場景。如果在填入相同索引鍵之前對該索引鍵發出多個並行 GetEntry 請求,則只會呼叫一次備用 LoadEntry 服務。LoadEntry 呼叫完成後,所有待處理 GetEntry 請求將傳回擷取到的值。
如需提供 LoadEntry 服務實行的詳細資訊,請參閱上面的「取代 LoadEntry 服務」一節。
指標
有幾個與快取相關的指標可用。在高可用性 (HA) 環境中,每個節點的快取都是獨立的。應使用 platformcache_name 標籤處理每個節點的指標。
以下是可用的快取指標:
快取指標
描述
thingworx_cache_hit_rate
導致在快取中找到項目的快取請求比例
thingworx_cache_hits
快取查詢方法已傳回快取值的次數
thingworx_cache_request_count
快取查詢方法已傳回快取或未快取值的次數
thingworx_cache_miss_rate
已傳回未快取 (新載入) 值或 null 之快取查詢方法的比率
thingworx_cache_misses
快取查詢方法已傳回未快取 (新載入) 值或 null 的次數
thingworx_cache_eviction_count
已收回項目的次數
thingworx_cache_average_load_penalty
載入新值所花費的平均時間
thingworx_cache_weighted_size
快取的目前逼近大小 (以位元組為單位)
thingworx_cache_max_weight
收回前的最大快取大小 (以位元組為單位)
thingworx_cache_estimated_entry_count
快取中的預估項目數
thingworx_cache_global_max_size
所有快取的全域最大配置大小 (以位元組為單位)
警示 (在 PTC 雲端服務託管環境中可用)
PTC 雲端服務託管環境中提供以下警示:
thingworxEntityCacheMissRate - 當快取的未命中率超過 80% 持續 1 小時時發出警示。
thingworxEntityCacheEvictions - 當快取的收回率超過 80% 持續 30 分鐘時發出警示。
範例與最佳實務
實行有效使用 CacheThing 的服務需要注意細節。請考慮下列最佳作法:
ThingWorx 節點重新啟動時,會清除快取。
項目可能會在沒有使用者動作的情況下從快取中收回或到期。不要假設項目將無限期地保留在快取中。
使用快取指標來驗證快取大小設定是否適當。
避免將所有資料儲存在單一項目下或建立非常大的快取項目。
在高可用性 (HA) 環境中,每個節點都有獨立快取。在一個節點中新增、刪除或清除快取不會影響所有 ThingWorx 節點。
當禁用「快取執行未命中項目的載入」(非通讀快取) 時:
1. 使用主索引鍵從快取中擷取項目。
2. 檢查是否已填入結果 (傳回的資料負載有一列)。
3. 如果找到結果,請使用該結果。
4. 如果找不到結果:
從來源資料 (例如,資料庫物件、資料表或 ContentLoader) 擷取或產生所需項目。
使用 PutEntry 將項目新增至快取。
傳回新快取的項目。
當啟用「快取執行未命中項目的載入」(通讀快取) 時:
1. 取代 CacheThing 中的 LoadEntry 服務。
2. 使用主索引鍵從快取中擷取項目。
如果找不到項目,LoadEntry 會自動呼叫以填入值。
使用 TimesTwo 服務的範例 
TimesTwo 服務會取一個數字,乘以 2,並將結果儲存在快取中。欲進行設定,請遵循下列步驟:
1. 使用下列欄位建立資料形式 (TimesTwoDataShape):operand: (LONG, primaryKey)timesTwoValue: (LONG)
2. 使用配置的 TimesTwoDataShape 建立 CacheThing (MyTimesTwoCache)。
3. TimesTwo 服務新增至 MyTimesTwoCache
輸入 - x (一個 LONG 數字)
輸出 - result (一個 LONG 數字)
// Input is x as a LONG
// Output is result as LONG
// MyTimesTwoCache CacheThing is configured with a DataShape with two fields:
// operand: (LONG, primaryKey)
// timesTwoValue: (LONG)
result = -1;
// Check the cache first, to see if we have already calculated x*2
// GetEntryByKey is a convenience method that takes the String value the configured DataShape's Primary Key ("key" in this example)
// cacheResult is an InfoTable with the DataShape of the cache
let cacheResult = Things["MyTimesTwoCache"].GetEntryByKey({ operand: x.toString() });
if (cacheResult.getRowCount() === 0) {
// Cache didn't have a result, so calculate it
let timesTwo = x*2;

// Put the result in the cache for the next time we need this multiple
// operand and value are from the Cache's configured DataShape
let cacheInput = getInfoTableForPut(x, timesTwo);
Things["MyTimesTwoCache"].PutEntry({
values: cacheInput
});

// Turn ScriptLogger to debug mode to see the logger messages
logger.debug("PutEntry the following entry into the MyTimesTwoCache: {operand: " + x + ", timesTwoValue: " + timesTwo + "}");

// Set the global result Output variable
result = timesTwo;
} else {
// If results are found, they are always in the first row of the InfoTable
let row = cacheResult.getRow(0);
logger.debug("Found the following entry already in MyTimesTwoCache: {operand: " + row.operand + ", timesTwoValue: " + row.timesTwoValue + "}");
result = row.timesTwoValue;
}
function getInfoTableForPut(operand, timesTwoValue) {
let infoTable = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: Things["MyTimesTwoCache"].GetDataShape()
});
infoTable.AddRow({"operand": operand, "timesTwoValue ": timesTwoValue });
return infoTable;
}
快取服務包裝函式範例 
此範例示範如何手動快取 QueryImplementingThingsV2 服務的結果。
1. 使用下列欄位建立名為 Cached_QueryImplementingThingsV2_DataShape 的資料形式:
maxItems: (NUMBER, primaryKey)
nameMask: (STRING, primaryKey)
query: (QUERY, primaryKey)
isSortFirst: (BOOLEAN, primaryKey)
result: (INFOTABLE, DataShape RootEntityListV2)
2. 建立名為 Cached_QueryImplementingThingsV2 的 CacheThing,並將 Cached_QueryImplementingThingsV2_DataShape 指派為其資料形式。
3. 欲觀察快取到期行為,請配置簡短 ExpirationTime,並在 Cached_ReadThrough_QueryImplementingThingsV2 物件上設定 ExpirationPolicy,而非 Never
4. 使用下列參數建立名為 CachingQueryImplementingThingsV2 的服務:
輸入
maxItems: (NUMBER, required)
nameMask: (STRING, required)
query: (QUERY, required)
isSortFirst: (BOOLEAN, required)
輸出 result: (INFOTABLE, DataShape RootEntityListV2)
/* 
This Service queries QueryImplementingThingsV2 and caches the results as needed
Service Name: CachingQueryImplementingThingsV2 (Overridden on CacheThing)
Input: values InfoTable with Cached_QueryImplementingThingsV2_DataShape
Cached_QueryImplementingThingsV2_DataShape:
maxItems: NUMBER, Primary Key
nameMask: STRING, Primary Key
query: QUERY, Primary Key
isSortFirst: BOOLEAN, Primary Key
result: INFOTABLE, DataShape RootEntityListV2 (NOT a Primary Key!)
*/
let cacheEntryInfoTable = getCacheEntryInfoTable();
cacheEntryInfoTable.AddRow({
maxItems: maxItems /* NUMBER */,
nameMask: nameMask /* STRING */,
query: query /* QUERY */,
isSortFirst: isSortFirst /* BOOLEAN */
});
let getEntryResult = me.GetEntry({values: cacheEntryInfoTable});
if (getEntryResult.getRowCount() === 0) {
// Cache didn't have results, so call QueryImplementingThingsV2
let queryResult = ThingTemplates["GenericThing"].QueryImplementingThingsV2({
maxItems: maxItems /* NUMBER */,
nameMask: nameMask /* STRING */,
query: query /* QUERY */,
isSortFirst: isSortFirst /* BOOLEAN */
});

// Add the result to the cache, with the primaryKey parameters used to uniquely identify the query.
let newCacheEntryInfoTable = getCacheEntryInfoTable();
newCacheEntryInfoTable.AddRow({
maxItems: maxItems /* NUMBER */,
nameMask: nameMask /* STRING */,
query: query /* QUERY */,
isSortFirst: isSortFirst /* BOOLEAN */,
result: queryResult /* INFOTABLE */
});
me.PutEntry({
values: newCacheEntryInfoTable
});
logger.debug("Entry not found in Cache, retrieved from QueryImplementingThingsV2:" + queryResult.ToJSON());
result = queryResult;
} else {
logger.debug("Found entry from Cache:" + getEntryResult.ToJSON());
let row = getEntryResult.getRow(0);
result = row.result;
}

function getCacheEntryInfoTable() {
return Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: "Cached_QueryImplementingThingsV2_DataShape"
});
}
將服務包裝函式快取為通讀快取範例 
此範例示範如何使用通讀快取自動快取 QueryImplementingThingsV2 服務的結果。取代 LoadEntry 服務之後,您可以使用 GetEntry 服務來將 QueryImplementingThingsV2 查詢結果自動載入快取中。
1. 使用下列欄位建立名為 Cached_QueryImplementingThingsV2_DataShape 的資料形式:
maxItems: (NUMBER, primaryKey)
nameMask: (STRING, primaryKey)
query: (QUERY, primaryKey)
isSortFirst: (BOOLEAN, primaryKey)
result: (INFOTABLE, DataShape RootEntityListV2)
2. 建立名為 Cached_ReadThrough_QueryImplementingThingsV2 的 CacheThing。將 Cached_QueryImplementingThingsV2_DataShape 指派為其資料形式,並啟用「快取執行未命中項目的載入」選項。
3. 欲觀察快取到期行為,請配置簡短 ExpirationTime,並在 Cached_ReadThrough_QueryImplementingThingsV2 物件上設定 ExpirationPolicy,而非 Never
4. 前往「服務」標籤,並選取 LoadEntry 服務旁邊的「取代」,範例如下:
/* 
This Service simply proxies a query to QueryImplementingThingsV2 for Read Through caching
Service Name: LoadEntry (Overridden on CacheThing)
Input: values InfoTable with Cached_QueryImplementingThingsV2_DataShape
Cached_QueryImplementingThingsV2_DataShape:
maxItems: NUMBER, Primary Key
nameMask: STRING, Primary Key
query: QUERY, Primary Key
isSortFirst: BOOLEAN, Primary Key
result: INFOTABLE, DataShape RootEntityListV2 (NOT a Primary Key!)
*/
let queryResult = ThingTemplates["GenericThing"].QueryImplementingThingsV2({
maxItems: values.maxItems /* NUMBER */,
nameMask: values.nameMask /* STRING */,
query: values.query /* QUERY */,
isSortFirst: values.isSortFirst /* BOOLEAN */
});
// Copy the results into a new InfoTable.
// This prevents some internal ThingWorx casting issues with some InfoTables
let resultTable = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: me.GetDataShape() // Returns Cached_QueryImplementingThingsV2_DataShape
});
resultTable.AddRow({
maxItems: values.maxItems /* NUMBER {"defaultValue":500} */,
nameMask: values.nameMask /* STRING */,
query: values.query /* QUERY */,
isSortFirst: values.isSortFirst /* BOOLEAN */,
result: queryResult
});
let result = resultTable;
使用 DataTableQuery 的範例 
此範例示範如何使用有效的 BetweenDatesDataTableQuery 服務來尋找資料表中兩個日期之間的最大值,以及如何將結果儲存在快取中。對於 CachingBetweenDatesDataTableQuery 的唯一呼叫一開始會查詢備用資料表,但後續的相同呼叫則會改用快取。
欲進行設定,請遵循下列步驟:
1. 使用下列欄位建立資料形式 (TimeValueDataShape):longKey: (LONG, primaryKey)dateKey: (DATETIME, primaryKey)
2. 使用 TimeValueDataShape 資料形式建立資料表 (DemoDataTable)。
3. 使用下列欄位建立資料形式 (TimeSpanValueCacheDataShape):startDate: (DATETIME, primaryKey)endDate: (DATETIME, primaryKey)longValue: (LONG)
4. 使用配置的 TimeSpanValueCacheDataShape 資料形式建立 CacheThing (CacheThingDemo)。
5. CacheThingDemo 上建立下列服務:
CachingBetweenDatesDataTableQuery - 輸入:StartDateEndDate 作為 DATETIME。輸出:result 作為 LONG
BetweenDatesDataTableQuery - 輸入:StartDateEndDate 作為 DATETIME。輸出:result 作為 LONG
* 
此服務會將示範資料自動填入到資料表中的查詢日期範圍內。
6. 選用。在 CacheThingDemo 上使用 ExpirationPolicy 而非 Never 來配置短 ExpirationTime,以觀察快取中已到期的項目。
CachingBetweenDatesDataTableQuery
/* Reads the Cached results of BetweenDatesDataTableQuery Service.
If Cache doesn't have the result, call BetweenDatesDataTableQuery and load results into Cache.

Service Name: CachingBetweenDatesDataTableQuery
Inputs: StartDate[DATETIME, required], EndDate[DATETIME, required]
Output: LONG
*/
// This example uses CacheThing.GetEntry, which requires a one-row infoTable populated with the CacheThing's DataShapes primaryKey getEntryByKey
let cacheEntryInfoTable = getCacheEntryInfoTable();
cacheEntryInfoTable.AddRow({"startDate": StartDate, "endDate": EndDate});
let getEntryResult = Things["CacheThingDemo"].GetEntry({
values: cacheEntryInfoTable
});
if (getEntryResult.getRowCount() === 0) {
// Cache didn't have results, so go to backing DataTable, by calling the BetweenDatesDataTableQuery Service
let queryResult = Things["CacheThingDemo"].BetweenDatesDataTableQuery({
StartDate: StartDate,
EndDate: EndDate
});

// Turn ScriptLogger to debug mode to see the logger messages
logger.debug("PutEntry called for BetweenDatesQueryCache: {StartDate: " + StartDate + ", EndDate: " + EndDate + " value: " + queryResult + "}");
if (!queryResult || queryResult < 0) {
// BetweenDatesDataTableQuery should always populate with demo data if no data is in the StartDate - EndDate range
throw new Error("BetweenDatesDataTableQuery did not return results");
}
let newCacheEntryInfoTable = getCacheEntryInfoTable();
newCacheEntryInfoTable.AddRow({"startDate": StartDate, "endDate": EndDate, "longValue": queryResult});
Things["CacheThingDemo"].PutEntry({
values: newCacheEntryInfoTable
});
result = queryResult;
} else {
let row = getEntryResult.getRow(0);
logger.debug("Found the following entry already in Cache : {StartDate: " + row.startDate + ", EndDate: " + row.endDate + ", LongValue: " + row.longValue + "}");
result = row.longValue;
}
function getCacheEntryInfoTable() {
return Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: "TimeSpanValueCacheDataShape"
});
}
BetweenDatesDataTableQuery
/*  This service queries a range of dates, based on the dateKey column, and returns the greatest longKey value found.
If there are no entries between StartDate and EndDate this Service dynamically populates demo data into demoDataTable, and returns that result.

Service Name: BetweenDatesDataTableQuery
Inputs: StartDate[DATETIME, required], EndDate[DATETIME, required]
Output: LONG
*/
if (StartDate >= EndDate) {
throw Error("StartDate must be before EndDate");
}
let dataTable = Things["DemoDataTable"];
let queryResult = queryGreatestLongKeyBetweenDates(dataTable, StartDate, EndDate);
if (queryResult.getRowCount() === 0) {
// If we don't get any results, first populate the date range with random values, then retry
// Turn ScriptLogger to debug mode to see the logger messages
logger.debug("No values found between [" + StartDate + "] and [" + EndDate + "], populating 100 demo values and re-querying");
populateDemoDataTable(dataTable, StartDate, EndDate);
// Re-query the now populated DateTable
queryResult = queryGreatestLongKeyBetweenDates(dataTable, StartDate, EndDate);
result = queryResult.getRow(0).get("longKey");
} else {
result = queryResult.getRow(0).get("longKey");
}
// Queries the DataTable for the largest longKey column value between the given dates
// Returns: One-row InfoTable with the found row.
function queryGreatestLongKeyBetweenDates(dateTable, startDate, endDate) {
let greatestBetweenDatesQuery = {
"filters": {
"type": "Between",
"fieldName": "dateKey",
"from": startDate,
"to": endDate
},
"sorts": [{
"fieldName": "longKey",
"isAscending": false
}]
};
// Run the Query to find the greatest Value Between Two Dates
let queryResult = dataTable.QueryDataTableEntries({
maxItems: 1,
query: greatestBetweenDatesQuery,
});

logger.debug("Queried between [" + StartDate + "] and [" + EndDate + "], found:" + queryResult.toJSON());
return queryResult;
}
function populateDemoDataTable(dataTable, startDate, endDate) {
// add 100 random entries between startDate and endDate
for (let entry = 0; entry < 100; entry++) {
let randomTimeBetween = randomDate(startDate, endDate);
let entry = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: "TimeValueDataShape"
});
entry.AddRow({
"longKey": Math.floor(Math.random() * 1000),
"dateKey": randomTimeBetween
});
Things["DemoDataTable"].AddDataTableEntry({
values: entry /* INFOTABLE */ ,
});
}
}
function randomDate(startDate, endDate) {
let randomTime = Math.random() * (endDate.getTime() - startDate.getTime()) + startDate.getTime();
return new Date(randomTime);
}
這是否有幫助?