diff --git a/Documentation/5.3/Raven.Documentation.Pages/document-extensions/timeseries/querying/overview-and-syntax.markdown b/Documentation/5.3/Raven.Documentation.Pages/document-extensions/timeseries/querying/overview-and-syntax.markdown index 056e3505d4..a9944bbf87 100644 --- a/Documentation/5.3/Raven.Documentation.Pages/document-extensions/timeseries/querying/overview-and-syntax.markdown +++ b/Documentation/5.3/Raven.Documentation.Pages/document-extensions/timeseries/querying/overview-and-syntax.markdown @@ -37,7 +37,7 @@ Time series query can - time series entries by their tags, values and timestamps. * [Aggregate](../../../document-extensions/timeseries/querying/aggregation-and-projections) time series entries into groups by a chosen time resolution, e.g. gather the prices - of a stock that's been collected over the past two months to week-long groups). Entries can + of a stock that's been collected over the past two months to week-long groups. Entries can also be aggregated by their tags. * Select entries by various criteria, e.g. by the min and max values of each aggregated group, and [project](../../../document-extensions/timeseries/querying/aggregation-and-projections) diff --git a/Documentation/6.0/Raven.Documentation.Pages/document-extensions/timeseries/querying/images/time-series-query.png b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/timeseries/querying/images/time-series-query.png similarity index 100% rename from Documentation/6.0/Raven.Documentation.Pages/document-extensions/timeseries/querying/images/time-series-query.png rename to Documentation/5.4/Raven.Documentation.Pages/document-extensions/timeseries/querying/images/time-series-query.png diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/timeseries/querying/overview-and-syntax.dotnet.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/timeseries/querying/overview-and-syntax.dotnet.markdown new file mode 100644 index 0000000000..7ab9e76b7f --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/timeseries/querying/overview-and-syntax.dotnet.markdown @@ -0,0 +1,283 @@ +# Querying Time Series: Overview & Syntax +--- + +{NOTE: } + +* Querying time series entries enables comprehending how a process gradually populates a time series over time and locating documents related to chosen time series entries. + +* Querying time series data is native to RavenDB's queries. + Clients can express time series queries in high-level LINQ expressions or directly in [RQL](../../../client-api/session/querying/what-is-rql). + +* Queries can be executed as dynamic queries or over [time series indexes](../../../document-extensions/timeseries/indexing). + +* In this page: + * [Time series query capabilities](../../../document-extensions/timeseries/querying/overview-and-syntax#time-series-query-capabilities) + * [Server and client queries](../../../document-extensions/timeseries/querying/overview-and-syntax#server-and-client-queries) + * [Dynamic and index queries](../../../document-extensions/timeseries/querying/overview-and-syntax#dynamic-and-index-queries) + * [Scaling query results](../../../document-extensions/timeseries/querying/overview-and-syntax#scaling-query-results) + * [RQL syntax](../../../document-extensions/timeseries/querying/overview-and-syntax#rql-syntax) + * [`select timeseries` syntax](../../../document-extensions/timeseries/querying/overview-and-syntax#section) + * [`declare timeseries` syntax](../../../document-extensions/timeseries/querying/overview-and-syntax#section-1) + * [Combine time series and custom functions](../../../document-extensions/timeseries/querying/overview-and-syntax#combine-time-series-and-custom-functions) + * [Use Studio To experiment](../../../document-extensions/timeseries/querying/overview-and-syntax#use-studio-to-experiment) + +{NOTE/} + +--- + +{PANEL: Time series query capabilities} + +Time series query can - + +* [Choose a range of time series entries](../../../document-extensions/timeseries/querying/choosing-query-range) to query from. +* [Filter](../../../document-extensions/timeseries/querying/filtering) time series entries by their tags, values and timestamps. +* [Aggregate](../../../document-extensions/timeseries/querying/aggregation-and-projections) time series entries into groups by a chosen time resolution, + e.g. gather the prices of a stock that's been collected over the past two months to week-long groups. + Entries can also be aggregated by their tags. +* Select entries by various criteria, e.g. by the min and max values of each aggregated group, + and [project](../../../document-extensions/timeseries/querying/aggregation-and-projections) them to the client. +* Calculate [statistical measures](../../../document-extensions/timeseries/querying/statistics): the percentile, slope, or standard deviation of a time series. + +{PANEL/} + +{PANEL: Server and client queries} + +Time series queries are executed by the server and their results are projected to the client, +so they require very little client computation resources. + +* The server runs time series queries using RQL. +* Clients can phrase time series queries in **raw RQL** or using high level **LINQ expressions**. + High level queries are translated to RQL by the client before sending them to the server for execution. + +{PANEL/} + +{PANEL: Dynamic and index queries} + +* **Dynamic queries**: + * Time series indexes are Not created automatically by the server when making a dynamic query. + * Use dynamic queries when time series you query are not indexed, + or when you prefer that RavenDB would choose an index automatically. See [queries always use an index](../../../client-api/session/querying/how-to-query#queries-always-provide-results-using-an-index). + E.g. - + + {CODE-BLOCK: javascript} +// Query for time series named "HeartRates" in employees hired after 1994 +from Employees as e +where HiredAt > "1994-01-01" +select timeseries( + from HeartRates +) + {CODE-BLOCK/} + +* **Index queries**: + * Static time series indexes can be created by clients (or using the Studio). + To learn how to create such indexes, see [indexing time series](document-extensions/timeseries/indexing). + * Examples of querying a static time series index can be found in [querying time series indexes](../../../document-extensions/timeseries/querying/using-indexes). + +{PANEL/} + +{PANEL: Scaling query results} + +* Time series query results can be **scaled**, multiplied by some number. + This doesn't change the values themselves, only the output of the query. + Scaling can serve as a stage in a data processing pipeline, or just for the purposes of displaying the data in a more understandable format. + +* There are several use cases for scaling. + For example, suppose your time series records the changing speeds of different vehicles as they travel through a city, + with some data measured in miles per hour and others in kilometers per hour. Here, scaling can facilitate unit conversion. + +* Another use case involves the compression of time series data. + Numbers with very high precision (i.e., many digits after the decimal point) are less compressible than numbers with low precision. + Therefore, for efficient storage, you might want to change a value like `0.000018` to `18` when storing the data. + Then, when querying the data, you can scale by `0.000001` to restore the original value. + +* Scaling is a part of both RQL and LINQ syntax: + + * In **LINQ**, use `.Scale()`. + * In **RQL**, use `scale ` in a time series query, and input your scaling factor as a double. + +--- + +#### Example: + +{CODE-TABS} +{CODE-TAB-BLOCK:csharp:LINQ} +var query = session.Query() + .Select(p => RavenQuery.TimeSeries(p, "HeartRates") + .Scale(10) + .ToList()) + .ToList(); + +// The value in the query results is 10 times the value stored on the server +var scaledValue = query[0].Results[0].Values[0]; +{CODE-TAB-BLOCK/} +{CODE-TAB-BLOCK:sql:RQL} +from Users +select timeseries( + from HeartRates + scale 10 +) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: RQL syntax} + +A typical time series query can start by locating the documents whose time series we want to query. +For example, we can query for employees above 30: + +{CODE-BLOCK: javascript} +from Employees as e +where Birthday < '1994-01-01' +{CODE-BLOCK/} + +Then, you can query their time series entries using either of the following two equivalent syntaxes: + +* [`select timeseries` syntax](../../../document-extensions/timeseries/querying/overview-and-syntax#section) +* [`declare timeseries` syntax](../../../document-extensions/timeseries/querying/overview-and-syntax#section-1) + +--- + +### `select timeseries` + +This syntax allows you to encapsulate your query's time series functionality in a `select timeseries` section. + +{CODE-BLOCK: javascript} +// Query for entries from time series "HeartRates" for employees above 30 +// ====================================================================== + +// This clause locates the documents whose time series we want to query: +from Employees as e +where Birthday < '1994-01-01' + +// Query the time series that belong to the matching documents: +select timeseries ( // The `select` clause defines the time series query. + from HeartRates // The `from` keyword is used to specify the time series name to query. +) +{CODE-BLOCK/} + +--- + +### `declare timeseries` + +This syntax allows you to declare a time series function (using `declare timeseries`) and call it from your query. +It introduces greater flexibility to your queries as you can, for example, pass arguments to the time series function. + +Here is a query written in both syntaxes. +It first queries for users above 30. If they possess a time series named "HeartRates", it retrieves a range of its entries. + +
+ +| With Time Series Function | Without Time Series Function | +|----------------------------|-------------------------------| +| {CODE-BLOCK: javascript} +// declare the time series function: +declare timeseries ts(jogger) { + from jogger.HeartRates + between + "2020-05-27T00:00:00.0000000Z" + and + "2020-06-23T00:00:00.0000000Z" +} + +from Users as jogger +where Age > 30 +// call the time series function +select ts(jogger) +{CODE-BLOCK/} | {CODE-BLOCK: javascript} +from Users as jogger +where Age > 30 +select timeseries( + from HeartRates + between + "2020-05-27T00:00:00.0000000Z" + and + "2020-06-23T00:00:00.0000000Z") + {CODE-BLOCK/} | + +{PANEL/} + +{PANEL: Combine time series and custom functions} + +* You can declare and use both time series functions and custom functions in a query. + The custom functions can call the time series functions, pass them arguments, and use their results. + +* In the example below, a custom function (`customFunc`) is called by the query `select` clause to fetch and format a set of time series entries, which are then projected by the query. + The time series function (`tsQuery`) is called to retrieve the matching time series entries. + +* The custom function returns a flat set of values rather than a nested array, to ease the projection of retrieved values. + +* Note the generated RQL in the second tab, where the custom function is translated to a [custom JavaScript function](../../../client-api/session/querying/what-is-rql#declare). + +{CODE-TABS} +{CODE-TAB:csharp:LINQ DefineCustomFunctions@DocumentExtensions\TimeSeries\TimeSeriesTests.cs /} +{CODE-TAB-BLOCK:javascript:RQL} +// The time series function: +// ========================= +declare timeseries tsQuery(user) { + from user.HeartRates + where (Values[0] > 100) +} + +// The custom JavaScript function: +// =============================== +declare function customFunc(user) { + var results = []; + + // Call the time series function to retrieve heart rate values for the user + var r = tsQuery(user); + + // Prepare the results + for(var i = 0 ; i < r.Results.length; i ++) { + results.push({ + Timestamp: r.Results[i].Timestamp, + Value: r.Results[i].Values.reduce((a, b) => Raven_Max(a, b)), + Tag: r.Results[i].Tag ?? "none"}) + } + return results; +} + +// Query & project results: +// ======================== +from "Users" as user +select + user.Name, + customFunc(user) as timeSeriesEntries // Call the custom JavaScript function +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +This is the custom `ModifiedTimeSeriesEntry` class that is used in the above LINQ sample: + +{CODE DefineCustomFunctions_ModifiedTimeSeriesEntry@DocumentExtensions\TimeSeries\TimeSeriesTests.cs /} + +{PANEL/} + +{PANEL: Use Studio to experiment} + +You can use the [Studio](../../../studio/database/document-extensions/time-series) to try the RQL samples provided in this article and test your own queries. + +!["Time Series Query in Studio"](images/time-series-query.png "Time Series Query in Studio") + +{PANEL/} + + +## Related articles + +**Time Series Overview** +[Time Series Overview](../../../document-extensions/timeseries/overview) + +**Studio Articles** +[Studio Time Series Management](../../../studio/database/document-extensions/time-series) + +**Time Series Indexing** +[Time Series Indexing](../../../document-extensions/timeseries/indexing) + +**Time Series Queries** +[Range Selection](../../../document-extensions/timeseries/querying/choosing-query-range) +[Filtering](../../../document-extensions/timeseries/querying/filtering) +[Aggregation and Projection](../../../document-extensions/timeseries/querying/aggregation-and-projections) +[Indexed Time Series Queries](../../../document-extensions/timeseries/querying/using-indexes) +[Statistical Measures](../../../document-extensions/timeseries/querying/statistics) + +**Policies** +[Time Series Rollup and Retention](../../../document-extensions/timeseries/rollup-and-retention) diff --git a/Documentation/5.4/Raven.Documentation.Pages/document-extensions/timeseries/querying/overview-and-syntax.js.markdown b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/timeseries/querying/overview-and-syntax.js.markdown new file mode 100644 index 0000000000..eeba42dd42 --- /dev/null +++ b/Documentation/5.4/Raven.Documentation.Pages/document-extensions/timeseries/querying/overview-and-syntax.js.markdown @@ -0,0 +1,265 @@ +# Querying Time Series: Overview & Syntax +--- + +{NOTE: } + +* Querying time series entries enables comprehending how a process gradually populates a time series over time and locating documents related to chosen time series entries. + +* Time series querying is native to RavenDB's queries. + Clients can express time series queries in high-level queries or directly in [RQL](../../../client-api/session/querying/what-is-rql). + +* Queries can be executed as dynamic queries or over [time series indexes](../../../document-extensions/timeseries/indexing). + +* In this page: + * [Time series query capabilities](../../../document-extensions/timeseries/querying/overview-and-syntax#time-series-query-capabilities) + * [Server and client queries](../../../document-extensions/timeseries/querying/overview-and-syntax#server-and-client-queries) + * [Dynamic and index queries](../../../document-extensions/timeseries/querying/overview-and-syntax#dynamic-and-index-queries) + * [Scaling query results](../../../document-extensions/timeseries/querying/overview-and-syntax#scaling-query-results) + * [RQL syntax](../../../document-extensions/timeseries/querying/overview-and-syntax#rql-syntax) + * [`select timeseries` syntax](../../../document-extensions/timeseries/querying/overview-and-syntax#section) + * [`declare timeseries` syntax](../../../document-extensions/timeseries/querying/overview-and-syntax#section-1) + * [Combine time series and custom functions](../../../document-extensions/timeseries/querying/overview-and-syntax#combine-time-series-and-custom-functions) + * [Use Studio To experiment](../../../document-extensions/timeseries/querying/overview-and-syntax#use-studio-to-experiment) + +{NOTE/} + +--- + +{PANEL: Time series query capabilities} + +Time series query can - + +* [Choose a range of time series entries](../../../document-extensions/timeseries/querying/choosing-query-range) to query from. +* [Filter](../../../document-extensions/timeseries/querying/filtering) time series entries by their tags, values and timestamps. +* [Aggregate](../../../document-extensions/timeseries/querying/aggregation-and-projections) time series entries into groups by a chosen time resolution, + e.g. gather the prices of a stock that's been collected over the past two months to week-long groups. + Entries can also be aggregated by their tags. +* Select entries by various criteria, e.g. by the min and max values of each aggregated group, + and [project](../../../document-extensions/timeseries/querying/aggregation-and-projections) them to the client. +* Calculate [statistical measures](../../../document-extensions/timeseries/querying/statistics): the percentile, slope, or standard deviation of a time series. + +{PANEL/} + +{PANEL: Server and client queries} + +Time series queries are executed by the server and their results are projected to the client, +so they require very little client computation resources. + +* The server runs time series queries using RQL. +* Clients can phrase time series queries in **raw RQL** or using **high level queries**. + High level queries are translated to RQL by the client before sending them to the server for execution. + +{PANEL/} + +{PANEL: Dynamic and index queries} + +* **Dynamic queries**: + * Time series indexes are Not created automatically by the server when making a dynamic query. + * Use dynamic queries when time series you query are not indexed, + or when you prefer that RavenDB would choose an index automatically. See [queries always use an index](../../../client-api/session/querying/how-to-query#queries-always-provide-results-using-an-index). + E.g. - + + {CODE-TABS} + {CODE-TAB:nodejs:Query overview_1@documentExtensions\timeSeries\querying\queryOverview.js /} + {CODE-TAB-BLOCK:sql:RQL} +from "employees" as e +where HiredAt > "1994-01-01" +select timeseries ( + from HeartRates +) + {CODE-TAB-BLOCK/} + {CODE-TABS/} + +* **Index queries**: + * Static time series indexes can be created by clients (or using the Studio). + To learn how to create such indexes, see [indexing time series](document-extensions/timeseries/indexing). + * Examples of querying a static time series index can be found in [querying time series indexes](../../../document-extensions/timeseries/querying/using-indexes). + +{PANEL/} + +{PANEL: Scaling query results} + +* Time series query results can be **scaled**, multiplied by some number. + This doesn't change the values themselves, only the output of the query. + Scaling can serve as a stage in a data processing pipeline, or just for the purposes of displaying the data in a more understandable format. + +* There are several use cases for scaling. + For example, suppose your time series records the changing speeds of different vehicles as they travel through a city, + with some data measured in miles per hour and others in kilometers per hour. Here, scaling can facilitate unit conversion. + +* Another use case involves the compression of time series data. + Numbers with very high precision (i.e., many digits after the decimal point) are less compressible than numbers with low precision. + Therefore, for efficient storage, you might want to change a value like `0.000018` to `18` when storing the data. + Then, when querying the data, you can scale by `0.000001` to restore the original value. + +--- + +#### Example: + +{CODE-TABS} +{CODE-TAB:nodejs:Query overview_2@documentExtensions\timeSeries\querying\queryOverview.js /} +{CODE-TAB-BLOCK:sql:RQL} +from "users" +select timeseries( + from HeartRates + scale 10 +) +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: RQL syntax} + +A typical time series query can start by locating the documents whose time series we want to query. +For example, we can query for employees above 30: + +{CODE-BLOCK: javascript} +from Employees as e +where Birthday < '1994-01-01' +{CODE-BLOCK/} + +Then, you can query their time series entries using either of the following two equivalent syntaxes: + +* [`select timeseries` syntax](../../../document-extensions/timeseries/querying/overview-and-syntax#section) +* [`declare timeseries` syntax](../../../document-extensions/timeseries/querying/overview-and-syntax#section-1) + +--- + +### `select timeseries` + +This syntax allows you to encapsulate your query's time series functionality in a `select timeseries` section. + +{CODE-BLOCK: javascript} +// Query for entries from time series "HeartRates" for employees above 30 +// ====================================================================== + +// This clause locates the documents whose time series we want to query: +from Employees as e +where Birthday < '1994-01-01' + +// Query the time series that belong to the matching documents: +select timeseries ( // The `select` clause defines the time series query. + from HeartRates // The `from` keyword is used to specify the time series name to query. +) +{CODE-BLOCK/} + +--- + +### `declare timeseries` + +This syntax allows you to declare a time series function (using `declare timeseries`) and call it from your query. +It introduces greater flexibility to your queries as you can, for example, pass arguments to the time series function. + +Here is a query written in both syntaxes. +It first queries for users above 30. If they possess a time series named "HeartRates", it retrieves a range of its entries. + +
+ +| With Time Series Function | Without Time Series Function | +|----------------------------|-------------------------------| +| {CODE-BLOCK: javascript} +// declare the time series function: +declare timeseries ts(jogger) { + from jogger.HeartRates + between + "2020-05-27T00:00:00.0000000Z" + and + "2020-06-23T00:00:00.0000000Z" +} + +from Users as jogger +where Age > 30 +// call the time series function +select ts(jogger) +{CODE-BLOCK/} | {CODE-BLOCK: javascript} +from Users as jogger +where Age > 30 +select timeseries( + from HeartRates + between + "2020-05-27T00:00:00.0000000Z" + and + "2020-06-23T00:00:00.0000000Z") + {CODE-BLOCK/} | + +{PANEL/} + +{PANEL: Combine time series and custom functions} + +* You can declare and use both time series functions and [custom JavaScript function](../../../client-api/session/querying/what-is-rql#declare) in a query. + The custom functions can call the time series functions, pass them arguments, and use their results. + +* In the example below, a custom function (`customFunc`) is called by the query `select` clause to fetch and format a set of time series entries, which are then projected by the query. + The time series function (`tsQuery`) is called to retrieve the matching time series entries. + +* The custom function returns a flat set of values rather than a nested array, to ease the projection of retrieved values. + +{CODE-TABS} +{CODE-TAB:nodejs:Query overview_3@documentExtensions\timeSeries\querying\queryOverview.js /} +{CODE-TAB-BLOCK:javascript:RQL} +// The time series function: +// ========================= +declare timeseries tsQuery(user) { + from user.HeartRates + where (Values[0] > 100.0) +} + +// The custom JavaScript function: +// =============================== +declare function customFunc(user) { + var results = []; + + // Call the time series function to retrieve heart rate values for the user + var r = tsQuery(user); + + // Prepare the results + for(var i = 0 ; i < r.Results.length; i ++) { + results.push({ + timestamp: r.Results[i].Timestamp, + value: r.Results[i].Values.reduce((a, b) => Raven_Max(a, b)), + tag: r.Results[i].Tag ?? "none"}) + } + return results; +} + +// Query & project results: +// ======================== +from "users" as user +select + user.name, + customFunc(user) as timeSeriesEntries // Call the custom JavaScript function +{CODE-TAB-BLOCK/} +{CODE-TABS/} + +{PANEL/} + +{PANEL: Use Studio to experiment} + +You can use the [Studio](../../../studio/database/document-extensions/time-series) to try the RQL samples provided in this article and test your own queries. + +!["Time Series Query in Studio"](images/time-series-query.png "Time Series Query in Studio") + +{PANEL/} + + +## Related articles + +**Time Series Overview** +[Time Series Overview](../../../document-extensions/timeseries/overview) + +**Studio Articles** +[Studio Time Series Management](../../../studio/database/document-extensions/time-series) + +**Time Series Indexing** +[Time Series Indexing](../../../document-extensions/timeseries/indexing) + +**Time Series Queries** +[Range Selection](../../../document-extensions/timeseries/querying/choosing-query-range) +[Filtering](../../../document-extensions/timeseries/querying/filtering) +[Aggregation and Projection](../../../document-extensions/timeseries/querying/aggregation-and-projections) +[Indexed Time Series Queries](../../../document-extensions/timeseries/querying/using-indexes) +[Statistical Measures](../../../document-extensions/timeseries/querying/statistics) + +**Policies** +[Time Series Rollup and Retention](../../../document-extensions/timeseries/rollup-and-retention) diff --git a/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/TimeSeries/TimeSeriesTests.cs b/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/TimeSeries/TimeSeriesTests.cs index 35b66a6c67..3907246951 100644 --- a/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/TimeSeries/TimeSeriesTests.cs +++ b/Documentation/5.4/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/TimeSeries/TimeSeriesTests.cs @@ -2710,39 +2710,43 @@ public async Task IndexQuery() .ToListAsync(); } #endregion - - } } - - // Patching:multiple time-series entries Using session.Advanced.Defer [Fact] public void QueryWithJavascriptAndTimeseriesFunctions() { using (var store = getDocumentStore()) { - // Create a document using (var session = store.OpenSession()) { #region DefineCustomFunctions - var query = from person in session.Query() - let customFunc = new Func, - IEnumerable>(entries => - entries.Select(e => new ModifiedTimeSeriesEntry - { - Timestamp = e.Timestamp, - Value = e.Values.Max(), - Tag = e.Tag ?? "none" - })) - let tsQuery = RavenQuery.TimeSeries(person, "Heartrate") - .Where(entry => entry.Values[0] > 100) - .ToList() - select new + var query = from user in session.Query() + + // The custom function + let customFunc = new Func, IEnumerable>( + entries => + entries.Select(e => new ModifiedTimeSeriesEntry { - Id = person.Id, - ModifiedTimeSeriesResults = customFunc(tsQuery.Results) - }; + Timestamp = e.Timestamp, + Value = e.Values.Max(), + Tag = e.Tag ?? "none" + })) + + // The time series query + let tsQuery = RavenQuery.TimeSeries(user, "HeartRates") + .Where(entry => entry.Values[0] > 100) + .ToList() + + // Project query results + select new + { + Name = user.Name, + // Call the custom function + TimeSeriesEntries = customFunc(tsQuery.Results) + }; + + var queryResults = query.ToList(); #endregion } } diff --git a/Documentation/5.4/Samples/nodejs/documentExtensions/timeSeries/querying/queryOverview.js b/Documentation/5.4/Samples/nodejs/documentExtensions/timeSeries/querying/queryOverview.js new file mode 100644 index 0000000000..e04b2d2330 --- /dev/null +++ b/Documentation/5.4/Samples/nodejs/documentExtensions/timeSeries/querying/queryOverview.js @@ -0,0 +1,88 @@ +import { DocumentStore } from "ravendb"; + +const documentStore = new DocumentStore(); +const session = documentStore.openSession(); + +async function queryOverview() { + { + //region overview_1 + // Define the time series query text + const tsQueryText = "from HeartRates"; + + // Make a dynamic query over the "employees" collection + const queryResults = await session.query({ collection: "employees" }) + // Query for employees hired after 1994 + .whereGreaterThan("HiredAt", "1994-01-01") + // Call 'selectTimeSeries' to project the time series entries in the query results + // Pass the defined time series query text + .selectTimeSeries(b => b.raw(tsQueryText), TimeSeriesRawResult) + .all(); + + // Results: + // ======== + + // 1. Results will include all entries from time series "HeartRates" for matching employee documents. + // 2. Since this is a dynamic query that filters documents, + // an auto-index (Auto/employees/ByHiredAt) will be created if it doesn't already exist. + // However, it is NOT a time series index !! + // It is a regular documents auto-index that allows querying for documents based on their HiredAt field. + + // Access a time series entry value from the results: + const entryValue = queryResults[0].results[0].values[0]; + //endregion + } + { + //region overview_2 + // Add 'scale ' to your time series query text + const tsQueryText = "from HeartRates scale 10"; + + const queryResults = await session.query({ collection: "users" }) + .selectTimeSeries(b => b.raw(tsQueryText), TimeSeriesRawResult) + .all(); + + // The value in the query results is 10 times the value stored on the server + const scaledValue = queryResults[0].results[0].values[0]; + //endregion + } + { + //region overview_3 + const queryResults = await session.advanced + // Provide RQL to rawQuery + .rawQuery(` + // The time series function: + // ========================= + declare timeseries tsQuery(user) { + from user.HeartRates + where (Values[0] > 100) + } + + // The custom JavaScript function: + // =============================== + declare function customFunc(user) { + var results = []; + + // Call the time series function to retrieve heart rate values for the user + var r = tsQuery(user); + + // Prepare the results + for(var i = 0 ; i < r.Results.length; i ++) { + results.push({ + timestamp: r.Results[i].Timestamp, + value: r.Results[i].Values.reduce((a, b) => Raven_Max(a, b)), + tag: r.Results[i].Tag ?? "none"}) + } + return results; + } + + // Query & project results: + // ======================== + from "users" as user + select + user.name, + customFunc(user) as timeSeriesEntries // Call the custom JavaScript function + `) + // Execute the query + .all(); + //endregion + } +} diff --git a/Documentation/6.0/Raven.Documentation.Pages/document-extensions/timeseries/querying/images/time-series-query.snag b/Documentation/6.0/Raven.Documentation.Pages/document-extensions/timeseries/querying/images/time-series-query.snag deleted file mode 100644 index b6f1cade9d..0000000000 Binary files a/Documentation/6.0/Raven.Documentation.Pages/document-extensions/timeseries/querying/images/time-series-query.snag and /dev/null differ diff --git a/Documentation/6.0/Raven.Documentation.Pages/document-extensions/timeseries/querying/overview-and-syntax.markdown b/Documentation/6.0/Raven.Documentation.Pages/document-extensions/timeseries/querying/overview-and-syntax.markdown deleted file mode 100644 index 931d572e0a..0000000000 --- a/Documentation/6.0/Raven.Documentation.Pages/document-extensions/timeseries/querying/overview-and-syntax.markdown +++ /dev/null @@ -1,299 +0,0 @@ -# Querying: Time Series Querying Overview & Syntax - ---- - -{NOTE: } - -* Time series querying is native to RavenDB's RQL. - -* Clients can express time series queries in RQL and LINQ expressions to, - for example, expose the behavior of a process that populates a time series - over time, and to locate documents related to chosen time series entries. - -* Queries can be executed over time series indexes. - -* In this page: - * [Time Series Queries](../../../document-extensions/timeseries/querying/overview-and-syntax#time-series-queries) - * [Server and Client Queries](../../../document-extensions/timeseries/querying/overview-and-syntax#server-and-client-queries) - * [Dynamic and Indexed Queries](../../../document-extensions/timeseries/querying/overview-and-syntax#dynamic-and-indexed-queries) - * [Scaling Query Results](../../../document-extensions/timeseries/querying/overview-and-syntax#scaling-query-results) - * [Syntax](../../../document-extensions/timeseries/querying/overview-and-syntax#syntax) - * [`select timeseries` syntax](../../../document-extensions/timeseries/querying/overview-and-syntax#syntax-creating-a-time-series-section) - * [`declare timeseries` syntax](../../../document-extensions/timeseries/querying/overview-and-syntax#syntax-declaring-a-time-series-function) - * [Combine Time Series and Javascript Functions](../../../document-extensions/timeseries/querying/overview-and-syntax#combine-time-series-and-javascript-functions) - * [Use Studio To Experiment](../../../document-extensions/timeseries/querying/overview-and-syntax#use-studio-to-experiment) - -{NOTE/} - ---- - -{PANEL: Time Series Queries} - -Time series query can - - -* [Choose a range of time series entries](../../../document-extensions/timeseries/querying/choosing-query-range) - to query from. -* [Filter](../../../document-extensions/timeseries/querying/filtering) - time series entries by their tags, values and timestamps. -* [Aggregate](../../../document-extensions/timeseries/querying/aggregation-and-projections) - time series entries into groups by a chosen time resolution, e.g. gather the prices - of a stock that's been collected over the past two months to week-long groups). Entries can - also be aggregated by their tags. -* Select entries by various criteria, e.g. by the min and max values of each aggregated group, - and [project](../../../document-extensions/timeseries/querying/aggregation-and-projections) - them to the client. -* Calculate [statistical measures](../../../document-extensions/timeseries/querying/statistics): - the percentile, slope, or standard deviation of a time series. - -{PANEL/} - -{PANEL: Server and Client Queries} - -Time series queries are executed by the server and their results are projected -to the client, so they require very little client computation resources. - -* The server runs time series queries using RQL. -* Clients can phrase time series queries in **raw RQL** or using **LINQ expressions** - (which will be automatically translated to RQL before their execution by the server). - -{PANEL/} - -{PANEL: Dynamic and Indexed Queries} - -Time series indexes are not created automatically by the server when making a dynamic query. -Static time series indexes can be created by clients (or using the Studio). - -* Use **dynamic queries** when time series you query are not indexed, - or when you prefer that RavenDB would choose an index automatically. - See [queries always use an index](../../../client-api/session/querying/how-to-query#queries-always-provide-results-using-an-index). E.g. - - {CODE-BLOCK: javascript} -//Look for time series named "HeartRates" in user profiles of users born after 1990 -from Employees as e -where Birthday > '1990-01-01' -select timeseries( - from HeartRates -) - {CODE-BLOCK/} - -* [Indexed queries](../../../document-extensions/timeseries/querying/using-indexes) - can be performed over static indexes and their results. E.g. - - {CODE-BLOCK: javascript} -from index 'SimpleIndex' -where Tag = 'watches/fitbit' - {CODE-BLOCK/} - -{PANEL/} - -{PANEL: Scaling Query Results} - -Time series query results can be **scaled**, multiplied by some number. This doesn't -change the values themselves, only the output of the query. This can serve as a stage -in a data processing pipeline, or just for the purposes of displaying the data in a -more undertandable format. - -There are many different use cases for this. For example, suppose your time series -records the changing speeds of different vehicles as they travel through a city, -but some of your data is in miles per hour, and some of it in kilometers per hour. In -this case scaling can be used for unit conversion. - -Another use case has to do with the compression of time series data. Numbers with -very high precision (i.e., many digits after the decimal point) are less compressible -than numbers with low precision. So for the purpose of storage, you might want to -change a value like `0.000018` to `18`. Then, when you query the data, you can scale -by `0.000001` to restore the original value. - -Scaling is a part of both RQL and LINQ syntax: - -* In **RQL**, use `scale ` in a time series query, and input your scaling - factor as a double. -* In **LINQ**, use `.Scale()`. - ---- - -#### Examples: - -{CODE-TABS} -{CODE-TAB-BLOCK:sql:RQL} -from Patients -select timeseries( - from HeartRate - scale 60 -) -{CODE-TAB-BLOCK/} -{CODE-TAB-BLOCK:csharp:LINQ} -var query = session.Query() - .Select(p => RavenQuery.TimeSeries(p, "HeartRate") - .Scale(60) - .ToList()); -{CODE-TAB-BLOCK/} -{CODE-TABS/} - -{PANEL/} - -{PANEL: Syntax} - -You can query time series using two equivalent syntaxes, -choose the syntax you're comfortable with. - -* [`select timeseries` syntax](../../../document-extensions/timeseries/querying/overview-and-syntax#syntax-creating-a-time-series-section) -* [`declare timeseries` syntax](../../../document-extensions/timeseries/querying/overview-and-syntax#syntax-declaring-a-time-series-function) - ---- - -#### `select timeseries` Syntax: Creating a Time Series Section - -This syntax allows you to encapsulate your query's time series functionality -in a `select timeseries` section. - -{CODE-BLOCK: javascript} -//Look for time series named "HeartRate" in user profiles of users under 30. - -from Employees as e -where Birthday > '1990-01-01' -select timeseries( - from HeartRate -) -{CODE-BLOCK/} - -* `from Employees as e where Birthday > '1990-01-01'` - This **document query** locates the documents whose time series we want to query. - - {INFO: } - A typical time series query starts by locating a single document. - For example, to query a time series of stock prices, we can first - locate a specific company's profile in the Companies collection, - and then query the StockPrices time series that belongs to this profile. - {CODE-BLOCK: javascript} - from Companies - where Name = 'Apple' - select timeseries( - from StockPrices - ) - {CODE-BLOCK/} - {INFO/} - -* `select timeseries` - The `select` clause defines the time series query. - -* `from HeartRate` - The `from` keyword is used to select the time series we'd query, by its name. - ---- - -#### `declare timeseries` Syntax: Declaring a Time Series Function - -This syntax allows you to declare a time series function and call it -from your query. It introduces greater flexibility to your queries as -you can, for example, pass arguments to/by the time series function. - -Here is a query in both syntaxes. It picks users whose age is under 30, -and if they own a time series named "HeartRate", retrieves a range of -its entries. - - -| With Time Series Function | Without Time Series Function | -|:---:|:---:| -| {CODE-BLOCK: javascript} -declare timeseries ts(jogger){ - from jogger.HeartRate - between - '2020-05-27T00:00:00.0000000Z' - and - '2020-06-23T00:00:00.0000000Z' -} - -from Users as jog where Age < 30 -select ts(jog) -{CODE-BLOCK/}| {CODE-BLOCK: javascript} - from Users as jog where Age < 30 - select timeseries( - from HeartRate - between - '2020-05-27T00:00:00.0000000Z' - and - '2020-06-23T00:00:00.0000000Z') - {CODE-BLOCK/}| - ---- - -#### Combine Time Series and Javascript Functions - -You can declare and use both **time series functions** and -[custom JavaScript functions](../../../client-api/session/querying/what-is-rql#declare) -in a query. -JavaScript functions can then call time series functions, pass them arguments, -use and manipulate their results. - -{NOTE: } -Custom Javascript functions return a flat set of values rather than a nested -array, to ease the projection of retrieved values. -{NOTE/} - -**In the sample below**, a Javascript function is called by the query's -`select` clause to fetch and format a set of time series values, which are then -projected by the query. -To retrieve the values, the Javascript function calls the time series function. - -{CODE-TABS} -{CODE-TAB-BLOCK:javascript:RQL} -declare timeseries retrieveHeartRateValues(e) -{ - from e.HeartRates -} - -declare function ts(e) { - // Call time series function to retrieve employees heartrate values - var r = retrieveHeartRateValues(e); - var results = []; - // structure the results - for(var i = 0 ; i < r.Results.length; i ++) { - results.push({ - Timestamp: r.Results[i].Timestamp, - Value: r.Results[i].Values[0].toFixed(2), - Tag: r.Results[i].Tag ?? "default"}) - } - return results; -} - -from Employees as e -// Call the custom Javascript function to get a structure of values to project -select ts(e) -{CODE-TAB-BLOCK/} -{CODE-TAB:csharp:LINQ DefineCustomFunctions@DocumentExtensions\TimeSeries\TimeSeriesTests.cs /} -{CODE-TABS/} - -This is the custom `ModifiedTimeSeriesEntry` class we use in the LINQ sample: -{CODE DefineCustomFunctions_ModifiedTimeSeriesEntry@DocumentExtensions\TimeSeries\TimeSeriesTests.cs /} - ---- - -#### Use Studio To Experiment - -You can use [Studio](../../../studio/database/document-extensions/time-series) -to try the samples provided here and test your own queries. - -!["Time Series Query in Studio"](images/time-series-query.png "Time Series Query in Studio") - -{PANEL/} - - -## Related articles - -**Time Series Overview** -[Time Series Overview](../../../document-extensions/timeseries/overview) - -**Studio Articles** -[Studio Time Series Management](../../../studio/database/document-extensions/time-series) - -**Time Series Indexing** -[Time Series Indexing](../../../document-extensions/timeseries/indexing) - -**Time Series Queries** -[Range Selection](../../../document-extensions/timeseries/querying/choosing-query-range) -[Filtering](../../../document-extensions/timeseries/querying/filtering) -[Aggregation and Projection](../../../document-extensions/timeseries/querying/aggregation-and-projections) -[Indexed Time Series Queries](../../../document-extensions/timeseries/querying/using-indexes) -[Statistical Measures](../../../document-extensions/timeseries/querying/statistics) - -**Policies** -[Time Series Rollup and Retention](../../../document-extensions/timeseries/rollup-and-retention) diff --git a/Documentation/6.0/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/TimeSeries/TimeSeriesTests.cs b/Documentation/6.0/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/TimeSeries/TimeSeriesTests.cs index f768718e5d..903864332d 100644 --- a/Documentation/6.0/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/TimeSeries/TimeSeriesTests.cs +++ b/Documentation/6.0/Samples/csharp/Raven.Documentation.Samples/DocumentExtensions/TimeSeries/TimeSeriesTests.cs @@ -2713,13 +2713,9 @@ public async Task IndexQuery() .ToListAsync(); } #endregion - - } } - - // Patching:multiple time-series entries Using session.Advanced.Defer [Fact] public void QueryWithJavascriptAndTimeseriesFunctions() { @@ -2729,23 +2725,32 @@ public void QueryWithJavascriptAndTimeseriesFunctions() using (var session = store.OpenSession()) { #region DefineCustomFunctions - var query = from person in session.Query() - let customFunc = new Func, - IEnumerable>(entries => - entries.Select(e => new ModifiedTimeSeriesEntry - { - Timestamp = e.Timestamp, - Value = e.Values.Max(), - Tag = e.Tag ?? "none" - })) - let tsQuery = RavenQuery.TimeSeries(person, "Heartrate") - .Where(entry => entry.Values[0] > 100) - .ToList() - select new + var query = from user in session.Query() + + // The custom function + let customFunc = new Func, IEnumerable>( + entries => + entries.Select(e => new ModifiedTimeSeriesEntry { - Id = person.Id, - ModifiedTimeSeriesResults = customFunc(tsQuery.Results) - }; + Timestamp = e.Timestamp, + Value = e.Values.Max(), + Tag = e.Tag ?? "none" + })) + + // The time series query + let tsQuery = RavenQuery.TimeSeries(user, "HeartRates") + .Where(entry => entry.Values[0] > 100) + .ToList() + + // Project query results + select new + { + Id = user.Name, + // Call the custom function + TimeSeriesEntries = customFunc(tsQuery.Results) + }; + + var queryResults = query.ToList(); #endregion } }