Skip to content

QueryAPI

Oliver Sturm edited this page Nov 5, 2020 · 8 revisions

The package devextreme-query-mongodb exports a function called query. It accepts a MongoDB collection, a loadOptions structure, and optionally processing options. Here is a simple example:

const MongoClient = require("mongodb").MongoClient;
const query = require("devextreme-query-mongodb");

async function queryData() {
  MongoClient.connect("mongodb://localhost:27017/testdatabase", (err, db) => {
    const results = await query(db.collection("values"), {
      // This is the loadOptions object - pass in any valid parameters
      take: 10,
      filter: [ "intval", ">", 47 ],
      sort: [ { selector: "intval", desc: true }]
    });

    // Now "results" contains an array of ten or fewer documents from the
    // "values" collection that have intval > 47, sorted descendingly by intval.
  });
}

Processing options

In addition to the collection and loadOptions parameters, the query function accepts an optional configuration object. Here is an overview of the available options, please see the sections below the table for details.

Option Details
replaceIds (default: true) - return _id field values as strings
summaryQueryLimit (default: 100) - safety net to protect against overly large numbers of per-group summary queries
timezoneOffset (default: 0) - facilitate handling of time zone differences between server and client for date/time field postfixes in filters or group definitions
caseInsensitiveRegex (default: true) - change case sensitivity of string filter and search criteria
aggregateOptions (default: unset) - specify options for the aggregate calls to the MongoDB collection
dynamicAggregateOptions (default: unset) - dynamically configure options for the aggregate calls to the MongoDB collection
preferMetadataCount (default: false) - not recommended for general use, see description! - prefer metadata based total-count mechanism

For clarity, a query call that passes processing options might look like this:

const results = await query(
  db.collection('values'),
  {
    filter: ['intval', '>', 47],
  },
  {
    // these are processing options
    replaceIds: false,
    timezoneOffset: new Date().getTimezoneOffset(),
  }
);

Processing option: replaceIds

replaceIds is set to true by default. The effect of this is that _id field values are returned as strings, instead of using the MongoDB internal object representation. The default value is set under the assumption that data will be passed on to parts of the application system where the origin of the id values should not be visible. Since MongoDB doesn't have a built-in mechanism (as far as I know) to return id values as strings, there is a certain overhead associated with this approach. In cases where you are going to process the data further using other MongoDB queries, or if you use your own structures for id values, it can increase performance to pass false for replaceIds.

Processing option: summaryQueryLimit

summaryQueryLimit is a safety-net for a situation where group queries are executed to return large result sets, and group summaries are required at the same time. Separate queries need to be executed internally to calculate various summaries, and if this is accidentally done for all groups it can result in an increase in processing time to the extent that other parts of your architecture encounter timeouts. Realistically this shouldn't happen as long as group queries are combined with reasonable take values. But with certain combinations of flags (server-side grouping and summaries, but no groupPaging) the Data Grid executes queries that result in this issue. The default summaryQueryLimit prevents more than 100 summaries from being calculated, which should suffice in most cases. If you want to deactivate this mechanism, set summaryQueryLimit to 0 (zero).

Processing option: timezoneOffset

timezoneOffset is set to 0 (zero) by default. It is relevant if you use field postfixes like Month or DayOfWeek (see loadOptions) for either filtering or grouping. MongoDB stores Date values in UTC time, using the server time zone to convert, and for the aggregation pipeline features that are used by devextreme-query-mongodb, it does not do anything to convert the values back to a client time zone. (There is an outstanding issue recorded for MongoDB to fix this behavior.)

By setting timezoneOffset to your client offset, you instruct devextreme-query-mongodb to modify the stored Date values by the offset before extracting the Month, DayOfWeek... details. The value used for this parameter should have the "format" returned by the function Date.getTimezoneOffset(). For instance, if your local time is one hour ahead of UTC, you should use -60 for timezoneOffset.

Note that this feature does not help in situations where your client time zone is different from the server one. In such cases, you need to convert time values on the client before persisting them, and convert them back after querying them.

Note that an issue tracks progress of an update to this feature.

Processing option: caseInsensitiveRegex

caseInsensitiveRegex is set to true by default.

Note that this is a breaking change in 2.0.9.

If the option is true, all $regex queries are run with the the i option to activate case insensitivity. This affects the operators startswith, endswith, contains and notcontains for filter and search criteria.

Processing option: aggregateOptions

Queries executed by devextreme-query-mongodb utilize the MongoDB function collection.aggregate. The function supports a set of options. Using the aggregateOptions option, the following options can be configured:

  • allowDiskUse
  • maxTimeMS
  • readConcern
  • collation
  • hint
  • comment

The object passed to aggregateOptions is filtered to contain only the supported values, but the resulting parameter object is passed directly to each aggregate call that is executed as part of a devextreme-query-mongodb query process.

Note that any individual call to the devextreme-query-mongodb query function can result in several calls to collection.aggregate. The same aggregateOptions will be passed to all such calls within the context of one query call.

Processing option: dynamicAggregateOptions

dynamicAggregateOptions can be set to a function, which will be called each time a MongoDB collection.aggregate call is executed. This is the function signature:

...
dynamicAggregateOptions: (identifier, pipeline, collection) => {
}
...

The identifier parameter can be used to find out which part of the query algorithm is currently being executed. Five different identifiers are currently used:

  • getCount
  • queryGroupData
  • augmentWithSummaries
  • summary
  • mainQueryResult

Unfortunately the meaning of each call within the context of the overall query algorithm is difficult to describe, which makes dynamicAggregateOptions an advanced feature. I recommend reading src/indexjs` to fully understand the algorithm.

The return value of dynamicAggregateOptions is used directly in the following call to collection.aggregate, but it is first filtered as described above for aggregateOptions.

Note that only one of aggregateOptions and dynamicAggregateOptions can be used at a time. dynamicAggregateOptions takes preference if included.

Processing option: preferMetadataCount

Note: Not recommended for general use! Please read the description carefully and make sure you understand the implications if you decide to use this option.

This issue describes research into the performance of different "count" mechanisms. devextreme-query-mongodb requires a "count" algorithm in several scenarios, and specifically the requireTotalCount load option can result in significant overhead for some queries. However, client components may require the total count to enable paging features.

MongoDB supports a metadata-based count function, but according to docs and tests with the Node driver this function is now deprecated since it doesn't render correct results in all cases.

This issue comment describes the conditions under which the option preferMetadataCount can be used in spite of the deprecation situation, to benefit from the faster "count" functionality.

Note that the feature may be removed in the future if the MongoDB driver changes.

Clone this wiki locally