Syncfusion AI Assistant

How can I help you?

Querying in Angular DataManager

15 Apr 202624 minutes to read

The Query class in Syncfusion® Angular DataManager is used to build structured queries that interact with a data source. The queries define operations such as filtering, sorting, paging, and grouping, making it easier to retrieve and manipulate data in a consistent way.

By combining DataManager with the Query class, data operations can be executed either locally or against a remote service, depending on the configuration. This approach ensures that data handling remains efficient and flexible across different scenarios.

Key capabilities of Query class:

  • Filtering: Retrieve records that match specific conditions.
  • Sorting: Arrange records in ascending or descending order.
  • Paging: Limit the number of records returned at once.
  • Grouping: Organize records into logical categories.

Specifying resource name using from

The Query class allows defining the source from which data should be retrieved. The from method specifies the resource name, such as a table or endpoint, and sets the context for all subsequent query operations. Once the resource is defined, filtering, sorting, paging, and other operations can be applied seamlessly to that target source.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { Component, OnInit } from '@angular/core';
import { DataManager, Query, ReturnOption, ODataV4Adaptor } from '@syncfusion/ej2-data';
import { CommonModule } from '@angular/common';
const SERVICE_URL =  'https://services.odata.org/V4/Northwind/Northwind.svc/';

@Component({

imports: [CommonModule],
standalone: true,
    selector: 'app-root',
    templateUrl: './app.template.html',
    styles: [
        `.e-table {
            border: solid 1px #e0e0e0;
            border-collapse: collapse;
            font-family: Roboto;
        }

        .e-table td, .e-table th {
            border-style: solid;
            border-width: 1px 0 0;
            border-color: #e0e0e0;
            display: table-cell;
            font-size: 14px;
            line-height: 20px;
            overflow: hidden;
            padding: 8px 21px;
            vertical-align: middle;
            white-space: nowrap;
            width: auto;
        }`
    ]
})
export class AppComponent implements OnInit {

    public items?: object[] | any;

    public ngOnInit(): void {
        new DataManager({ url: SERVICE_URL, adaptor: new ODataV4Adaptor()})
        .executeQuery(new Query().from('Orders').take(8)).then((e: ReturnOption) => this.items = e.result as object[]).catch((e) => true);
    }
}
<table class='e-table'>
    <tr><th>Order ID</th><th>Customer ID</th><th>Employee ID</th></tr>
    <tr *ngFor="let item of items">
        <td>{{item.OrderID}}</td><td>{{item.CustomerID}}</td><td>{{item.EmployeeID}}</td>
    </tr>
</table>
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Projection using select

The select method in the Query class is used to project specific fields from a data source. Instead of retrieving all columns, select allows choosing only the required fields. This reduces the amount of data returned, minimizes payload size, and improves performance by limiting unnecessary information.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { Component, OnInit } from '@angular/core';
import { DataManager, Query, ODataV4Adaptor, ReturnOption } from '@syncfusion/ej2-data';
import { CommonModule } from '@angular/common';

const SERVICE_URL = 'https://services.odata.org/V4/Northwind/Northwind.svc/Orders';

@Component({
    standalone: true,
    selector: 'app-root',
    imports: [CommonModule],
    templateUrl: './app.template.html',
    styles: [`
        .e-table {
            border: solid 1px #e0e0e0;
            border-collapse: collapse;
            font-family: Roboto, sans-serif;
        }

        .e-table td,
        .e-table th {
            border-style: solid;
            border-width: 1px 0 0;
            border-color: #e0e0e0;
            font-size: 14px;
            line-height: 20px;
            padding: 8px 21px;
            vertical-align: middle;
            white-space: nowrap;
        }
    `]
})
export class AppComponent implements OnInit {

    public items?: object[] | any;

    public ngOnInit(): void {
        new DataManager({ url: SERVICE_URL, adaptor: new ODataV4Adaptor()})
        .executeQuery(new Query().select(['OrderID', 'CustomerID', 'EmployeeID']).take(8))
        .then((e: ReturnOption) => this.items = e.result as object[]).catch((e) => true);
    }
}
<table class='e-table'>
    <tr><th>Order ID</th><th>Customer ID</th><th>Employee ID</th></tr>
    <tr *ngFor="let item of items">
        <td>{{item.OrderID}}</td><td>{{item.CustomerID}}</td><td>{{item.EmployeeID}}</td>
    </tr>
</table>
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

The expand method in the Query class is used to include related records when retrieving data. This technique, known as eager loading, ensures that navigation properties are fetched along with the main dataset. By expanding relationships, hierarchical or associated data can be accessed directly using dot‑separated field notation, making complex data retrieval more efficient.

import { Component, NgModule, OnInit } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { DataManager, Query, ODataV4Adaptor, ReturnOption } from '@syncfusion/ej2-data';
import { CommonModule } from '@angular/common';

const SERVICE_URL = 'https://services.odata.org/V4/Northwind/Northwind.svc/Orders';

@Component({
    standalone: true,
    selector: 'app-root',
    imports: [CommonModule],
    templateUrl: './app.template.html',
    styles: [`
        .e-table {
            border: solid 1px #e0e0e0;
            border-collapse: collapse;
            font-family: Roboto, sans-serif;
        }

        .e-table td,
        .e-table th {
            border-style: solid;
            border-width: 1px 0 0;
            border-color: #e0e0e0;
            font-size: 14px;
            line-height: 20px;
            padding: 8px 21px;
            vertical-align: middle;
            white-space: nowrap;
        }
    `]
})

export class AppComponent implements OnInit {

    public items?: object[] | any;

    public ngOnInit(): void {
        new DataManager({ url: SERVICE_URL, adaptor: new ODataV4Adaptor() })
        .executeQuery(new Query().expand('Employee').select(['OrderID', 'CustomerID', 'Employee.FirstName']).take(8))
        .then((e: ReturnOption) => this.items = e.result as object[]).catch((e) => true);
    }
}
<table class='e-table'>
    <tr><th>Order ID</th><th>Customer ID</th><th>Employee ID</th></tr>
    <tr *ngFor="let item of items">
        <td>{{item.OrderID}}</td><td>{{item.CustomerID}}</td><td>{{item.EmployeeID}}</td>
    </tr>
</table>
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Sorting

The sortBy method in the Query class arranges records in “ascending” order by default, while sortByDesc applies “descending” order. Alternatively, the descending parameter in sortBy can be used to specify sort direction. These methods enable precise control over data ordering based on selected fields.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { Component, OnInit } from '@angular/core';
import { DataManager, Query, ODataV4Adaptor, ReturnOption } from '@syncfusion/ej2-data';
import { CommonModule } from '@angular/common';

const SERVICE_URL = 'https://services.odata.org/V4/Northwind/Northwind.svc/Orders';

@Component({
    standalone: true,
    selector: 'app-root',
    imports: [CommonModule],
    templateUrl: './app.template.html',
    styles: [`
        .e-table {
            border: solid 1px #e0e0e0;
            border-collapse: collapse;
            font-family: Roboto, sans-serif;
        }

        .e-table td,
        .e-table th {
            border-style: solid;
            border-width: 1px 0 0;
            border-color: #e0e0e0;
            font-size: 14px;
            line-height: 20px;
            padding: 8px 21px;
            vertical-align: middle;
            white-space: nowrap;
        }
    `]
})
export class AppComponent implements OnInit {

    public items?: object[] | any;

    public ngOnInit(): void {
        new DataManager({ url: SERVICE_URL, adaptor: new ODataV4Adaptor()})
        .executeQuery(new Query().sortBy('CustomerID', 'descending').take(8))
        .then((e: ReturnOption) => this.items = e.result as object[]).catch((e) => true);
    }
}
<table class='e-table'>
    <tr><th>Order ID</th><th>Customer ID</th><th>Employee ID</th></tr>
    <tr *ngFor="let item of items">
        <td>{{item.OrderID}}</td><td>{{item.CustomerID}}</td><td>{{item.EmployeeID}}</td>
    </tr>
</table>
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Multi sorting can be performed by simply chaining the multiple sortBy methods.

Filtering

The where method in the Query class defines filter conditions to retrieve records that match specific criteria. Multiple filters can be combined using chainable syntax, enabling precise and efficient queries for complex scenarios.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { Component, OnInit } from '@angular/core';
import { DataManager, Query, ODataV4Adaptor, ReturnOption } from '@syncfusion/ej2-data';
import { CommonModule } from '@angular/common';

const SERVICE_URL = 'https://services.odata.org/V4/Northwind/Northwind.svc/Orders';

@Component({
    standalone: true,
    selector: 'app-root',
    imports: [CommonModule],
    templateUrl: './app.template.html',
    styles: [`
        .e-table {
            border: solid 1px #e0e0e0;
            border-collapse: collapse;
            font-family: Roboto, sans-serif;
        }

        .e-table td,
        .e-table th {
            border-style: solid;
            border-width: 1px 0 0;
            border-color: #e0e0e0;
            font-size: 14px;
            line-height: 20px;
            padding: 8px 21px;
            vertical-align: middle;
            white-space: nowrap;
        }
    `]
})
export class AppComponent implements OnInit {

    public items?: object[] | any;

    public ngOnInit(): void {
        new DataManager({ url: SERVICE_URL, adaptor: new ODataV4Adaptor()})
        .executeQuery(new Query().where('EmployeeID', 'equal', 3).take(8))
        .then((e: ReturnOption) => this.items = e.result as object[]).catch((e) => true);
    }
}
<table class='e-table'>
    <tr><th>Order ID</th><th>Customer ID</th><th>Employee ID</th></tr>
    <tr *ngFor="let item of items">
        <td>{{item.OrderID}}</td><td>{{item.CustomerID}}</td><td>{{item.EmployeeID}}</td>
    </tr>
</table>
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Filter Operators

Filter operators are generally used to specify the filter type. The various filter operators supported by DataManager is listed below.

  • greaterthan
  • greaterthanorequal
  • lessthan
  • lessthanorequal
  • equal
  • notequal
  • startswith
  • endswith
  • contains

These filter operators are used for creating filter query using where method and Predicate class.

Complex filter criteria using Predicate

The Predicate class enables advanced filtering by combining multiple conditions using logical operators like AND and OR. It offers a structured approach to building complex queries beyond simple chaining, supporting powerful and flexible data filtering.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { Component, OnInit } from '@angular/core';
import { DataManager, Query, ODataV4Adaptor, Predicate, ReturnOption } from '@syncfusion/ej2-data';
import { CommonModule } from '@angular/common';

const SERVICE_URL = 'https://services.odata.org/V4/Northwind/Northwind.svc/Orders';

@Component({
    standalone: true,
    selector: 'app-root',
    imports: [CommonModule],
    templateUrl: './app.template.html',
    styles: [`
        .e-table {
            border: solid 1px #e0e0e0;
            border-collapse: collapse;
            font-family: Roboto, sans-serif;
        }

        .e-table td,
        .e-table th {
            border-style: solid;
            border-width: 1px 0 0;
            border-color: #e0e0e0;
            font-size: 14px;
            line-height: 20px;
            padding: 8px 21px;
            vertical-align: middle;
            white-space: nowrap;
        }
    `]
})
export class AppComponent implements OnInit {

    public items?: object[] | any;

    public ngOnInit(): void {
        let predicate: Predicate = new Predicate('EmployeeID', 'equal', 3);
        predicate = predicate.or('EmployeeID', 'equal', 2);

        new DataManager({ url: SERVICE_URL, adaptor: new ODataV4Adaptor()})
        .executeQuery(new Query().where(predicate).take(8))
        .then((e: ReturnOption) => this.items = e.result as object[]).catch((e) => true);
    }
}
<table class='e-table'>
    <tr><th>Order ID</th><th>Customer ID</th><th>Employee ID</th></tr>
    <tr *ngFor="let item of items">
        <td>{{item.OrderID}}</td><td>{{item.CustomerID}}</td><td>{{item.EmployeeID}}</td>
    </tr>
</table>
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Searching

The search method in the Query class performs a global search by applying a keyword across all fields in the dataset. It retrieves records with matches in any column, enabling broad and efficient data exploration beyond field‑specific filtering.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { Component, OnInit } from '@angular/core';
import { DataManager, Query, ReturnOption } from '@syncfusion/ej2-data';
import { CommonModule } from '@angular/common';
import { data } from './datasource';

@Component({
    standalone: true,
    selector: 'app-root',
    imports: [CommonModule],
    templateUrl: './app.template.html',
    styles: [`
        .e-table {
            border: solid 1px #e0e0e0;
            border-collapse: collapse;
            font-family: Roboto, sans-serif;
        }

        .e-table td,
        .e-table th {
            border-style: solid;
            border-width: 1px 0 0;
            border-color: #e0e0e0;
            font-size: 14px;
            line-height: 20px;
            padding: 8px 21px;
            vertical-align: middle;
            white-space: nowrap;
        }
    `]
})
export class AppComponent implements OnInit {

    public items?: object[] | any;

    public ngOnInit(): void {
        new DataManager(data as JSON[])
        .executeQuery(new Query().search('VI', ['CustomerID']))
        .then((e: ReturnOption) => this.items = e.result as object[]).catch((e) => true);
    }
}
<table class='e-table'>
    <tr><th>Order ID</th><th>Customer ID</th><th>Employee ID</th></tr>
    <tr *ngFor="let item of items">
        <td>{{item.OrderID}}</td><td>{{item.CustomerID}}</td><td>{{item.EmployeeID}}</td>
    </tr>
</table>
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

To perform a search on specific fields, provide an array of field names as the second argument to the search method.

Grouping

The group method in the Query class organizes records into logical categories based on specified fields. This enables hierarchical structuring of data, making it easier to aggregate and present related records together. When combined with the DataManager, grouping supports efficient data analysis and visualization.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { Component, OnInit } from '@angular/core';
import { DataManager, Query, ODataV4Adaptor, ReturnOption } from '@syncfusion/ej2-data';
import { CommonModule } from '@angular/common';
import { GroupComponent } from './group.component';

const SERVICE_URL = 'https://services.odata.org/V4/Northwind/Northwind.svc/Orders';

@Component({
    standalone: true,
    selector: 'app-root',
    imports: [CommonModule, GroupComponent],
    templateUrl: './app.template.html',
    styles: [`
        .e-table {
            border: solid 1px #e0e0e0;
            border-collapse: collapse;
            font-family: Roboto, sans-serif;
        }

        .e-table td,
        .e-table th {
            border-style: solid;
            border-width: 1px 0 0;
            border-color: #e0e0e0;
            font-size: 14px;
            line-height: 20px;
            padding: 8px 21px;
            vertical-align: middle;
            white-space: nowrap;
        }
    `]
})
export class AppComponent implements OnInit {

    public items?: object[];

    public ngOnInit(): void {
        new DataManager({ url: SERVICE_URL, adaptor: new ODataV4Adaptor()})
        .executeQuery(new Query().group('CustomerID').take(8))
        .then((e: ReturnOption) => this.items = e.result as object[]).catch((e) => true);
    }
}
import { Component, OnInit, Input } from '@angular/core';
import { CommonModule } from '@angular/common';

@Component({
    standalone: true,
    selector: '[group]',              // Attribute selector used on <tbody>.
    imports: [CommonModule],
    template: `
    <tr><td> - </td><td></td><td></td></tr>
    <tr *ngFor="let item of data.items">
    <td></td><td></td><td></td>
    </tr>
    `,
    styles: [`
            td, th {
                border-style: solid;
                border-width: 1px 0 0;
                border-color: #e0e0e0;
                display: table-cell;
                font-size: 14px;
                line-height: 20px;
                overflow: hidden;
                padding: 8px 21px;
                vertical-align: middle;
                white-space: nowrap;
                width: auto;
            }`]
})
export class GroupComponent implements OnInit {
    @Input() public data?: object | any;
    ngOnInit() { }
}
<table class='e-table' >
    <tr>
        <th>Order ID</th>
        <th>Customer ID</th>
        <th>Employee ID</th>
    </tr>
    <tbody group *ngFor="let item of items" [data]='item' ></tbody>
</table>
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Multiple grouping can be done by simply chaining the group method.

Paging

The page method in the Query class retrieves records based on a specified page index and page size. This approach divides large datasets into smaller segments, improving performance and reducing memory consumption by loading only the required portion of data at a time.

import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { Component, OnInit } from '@angular/core';
import { DataManager, Query, ODataV4Adaptor, ReturnOption } from '@syncfusion/ej2-data';
import { CommonModule } from '@angular/common';

const SERVICE_URL = 'https://services.odata.org/V4/Northwind/Northwind.svc/Orders';

@Component({
    standalone: true,
    selector: 'app-root',
    imports: [CommonModule],
    templateUrl: './app.template.html',
    styles: [`
        .e-table {
            border: solid 1px #e0e0e0;
            border-collapse: collapse;
            font-family: Roboto, sans-serif;
        }

        .e-table td,
        .e-table th {
            border-style: solid;
            border-width: 1px 0 0;
            border-color: #e0e0e0;
            font-size: 14px;
            line-height: 20px;
            padding: 8px 21px;
            vertical-align: middle;
            white-space: nowrap;
        }
    `]
})
export class AppComponent implements OnInit {

    public items?: object[] | any;

    public ngOnInit(): void {
        new DataManager({ url: SERVICE_URL, adaptor: new ODataV4Adaptor()})
        .executeQuery(new Query().page(2, 8))
        .then((e: ReturnOption) => this.items = e.result as object[]).catch((e) => true);
    }
}
<table class='e-table'>
    <tr><th>Order ID</th><th>Customer ID</th><th>Employee ID</th></tr>
    <tr *ngFor="let item of items">
        <td>{{item.OrderID}}</td><td>{{item.CustomerID}}</td><td>{{item.EmployeeID}}</td>
    </tr>
</table>
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));

Aggregation

The aggregate method in the Query class computes statistical summaries such as sum, average, count, minimum, and maximum for specified fields within a dataset. This enables concise metric derivation, supporting analytical evaluation and reporting without requiring manual calculations.

The built-in aggregate types are,

  • sum
  • average
  • min
  • max
  • count
  • truecount
  • falsecount
import { NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { Component, OnInit } from '@angular/core';
import { DataManager, Query, ODataV4Adaptor, ReturnOption } from '@syncfusion/ej2-data';
import { CommonModule } from '@angular/common';

const SERVICE_URL = 'https://services.odata.org/V4/Northwind/Northwind.svc/Orders';

@Component({
    standalone: true,
    selector: 'app-root',
    imports: [CommonModule],
    templateUrl: './app.template.html',
    styles: [`
        .e-table {
            border: solid 1px #e0e0e0;
            border-collapse: collapse;
            font-family: Roboto, sans-serif;
        }

        .e-table td,
        .e-table th {
            border-style: solid;
            border-width: 1px 0 0;
            border-color: #e0e0e0;
            font-size: 14px;
            line-height: 20px;
            padding: 8px 21px;
            vertical-align: middle;
            white-space: nowrap;
        }
    `]
})
export class AppComponent implements OnInit {

    public items?: object[] | any;
    public min = 0;

    public ngOnInit(): void {
        new DataManager({ url: SERVICE_URL, adaptor: new ODataV4Adaptor()})
        .executeQuery(new Query().take(5).requiresCount().aggregate('min', 'EmployeeID'))
        .then((e: ReturnOption) => { this.items = e.result as object[];  this.min = (e as any).aggregates['EmployeeID - min']; }).catch((e) => true);
    }
}
<table class='e-table'>
    <tr><th>Order ID</th><th>Customer ID</th><th>Employee ID</th></tr>
    <tr *ngFor="let item of items">
        <td>{{item.OrderID}}</td><td>{{item.CustomerID}}</td><td>{{item.EmployeeID}}</td>
    </tr>
    <tr><td></td><td></td><td>Min: {{min}}</td></tr>
</table>
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import 'zone.js';
bootstrapApplication(AppComponent).catch((err) => console.error(err));