industrial-model 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +571 -537
- package/dist/cognite-core/index.cjs +1516 -0
- package/dist/cognite-core/index.cjs.map +1 -0
- package/dist/cognite-core/index.d.cts +532 -0
- package/dist/cognite-core/index.d.ts +532 -0
- package/dist/cognite-core/index.js +1513 -0
- package/dist/cognite-core/index.js.map +1 -0
- package/dist/index.cjs +260 -216
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -256
- package/dist/index.d.ts +3 -256
- package/dist/index.js +261 -215
- package/dist/index.js.map +1 -1
- package/dist/types-DCP5GMi3.d.cts +216 -0
- package/dist/types-DCP5GMi3.d.ts +216 -0
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -2,31 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
TypeScript SDK for querying [Cognite Flexible Data Models (FDM)](https://docs.cognite.com/cdf/data_modeling/) with a type-safe, graph-aware API.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
`industrial-model` is designed for application code that needs to move through industrial data as a model, not as loosely typed query payloads. Start with a Cognite data model, describe the view shape in TypeScript, and query nodes, relations, filters, sorting, pagination, and aggregations with compiler support.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
7
|
+
## What You Get
|
|
8
|
+
|
|
9
|
+
- **Typed model queries** - validate selected fields, filters, and sort keys at compile time.
|
|
10
|
+
- **Precise result types** - returned items follow the `select` tree, including nested relation selections.
|
|
11
|
+
- **Graph traversal** - expand direct, reverse, and edge relations up to 3 levels deep.
|
|
12
|
+
- **Industrial filters** - combine scalar filters, list filters, full-text search, and nested relation filters.
|
|
13
|
+
- **Pagination support** - use cursors manually or fetch all root pages with `limit: -1`.
|
|
14
|
+
- **Aggregation support** - count, group, list distinct values, and aggregate numeric properties.
|
|
15
|
+
- **Runtime validation option** - parse query results with Zod schemas derived from Cognite view metadata.
|
|
16
|
+
- **CJS and ESM builds** - works in Node.js and common bundler setups.
|
|
11
17
|
|
|
12
18
|
## Installation
|
|
13
19
|
|
|
14
20
|
```bash
|
|
15
21
|
npm install industrial-model
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
`@cognite/sdk` is a peer dependency and must be installed separately:
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
22
|
npm install @cognite/sdk
|
|
22
23
|
```
|
|
23
24
|
|
|
25
|
+
`@cognite/sdk` is a peer dependency and must be installed by your application.
|
|
26
|
+
|
|
24
27
|
## Requirements
|
|
25
28
|
|
|
26
29
|
- Node.js `>=20`
|
|
27
|
-
- `@cognite/sdk` `^10.10.0`
|
|
30
|
+
- `@cognite/sdk` `^10.10.0`
|
|
28
31
|
|
|
29
|
-
##
|
|
32
|
+
## First Query
|
|
33
|
+
|
|
34
|
+
Create a Cognite SDK client, point `IndustrialModelClient` at a data model, and query a view.
|
|
30
35
|
|
|
31
36
|
```ts
|
|
32
37
|
import { CogniteClient } from "@cognite/sdk";
|
|
@@ -47,58 +52,55 @@ const model = new IndustrialModelClient(client, {
|
|
|
47
52
|
|
|
48
53
|
const { items } = await model.query<{ name: string; description: string }>()({
|
|
49
54
|
viewExternalId: "CogniteAsset",
|
|
50
|
-
select: {
|
|
51
|
-
|
|
55
|
+
select: {
|
|
56
|
+
name: true,
|
|
57
|
+
description: true,
|
|
58
|
+
},
|
|
59
|
+
filters: {
|
|
60
|
+
name: { prefix: "Pump" },
|
|
61
|
+
},
|
|
62
|
+
sort: {
|
|
63
|
+
name: "ascending",
|
|
64
|
+
},
|
|
52
65
|
limit: 10,
|
|
53
66
|
});
|
|
67
|
+
|
|
68
|
+
items[0]?.name;
|
|
54
69
|
```
|
|
55
70
|
|
|
56
|
-
|
|
71
|
+
This is the basic contract:
|
|
57
72
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
| Relations | [Parent/root](#query-assets-with-parent-and-root-relations), [Path](#query-assets-with-their-full-path), [Children](#query-child-assets-reverse-relation), [Edges](#traverse-edge-relations-360-images-on-3d-objects) |
|
|
63
|
-
| Filters | [AND/OR/NOT](#combine-filters-with-and--or--not), [Nested](#filter-on-related-nodes), [Tags](#filter-assets-by-tags), [Batch IDs](#filter-by-multiple-external-ids) |
|
|
64
|
-
| Select & sort | [Select all scalars](#select-all-scalar-fields), [Multi-field sort](#sort-by-multiple-fields) |
|
|
65
|
-
| Pagination | [Manual cursor loop](#paginate-through-all-assets), [Fetch all pages](#fetch-all-pages-automatically) |
|
|
66
|
-
| Aggregation | [Count by group](#count-assets-by-source-id), [Distinct values](#list-distinct-source-ids), [Numeric aggregates](#average-volume-by-type), [Global count](#count-all-matching-assets) |
|
|
67
|
-
| Advanced | [Custom data model](#use-a-custom-data-model), [Full query](#full-example-assets-equipment-and-filters) |
|
|
73
|
+
1. `viewExternalId` selects the Cognite view.
|
|
74
|
+
2. The generic type describes the fields you want TypeScript to understand.
|
|
75
|
+
3. `select` controls the returned shape.
|
|
76
|
+
4. `filters`, `sort`, `limit`, and `cursor` control the query behavior.
|
|
68
77
|
|
|
69
|
-
|
|
78
|
+
## Define A Model
|
|
70
79
|
|
|
71
|
-
|
|
80
|
+
For scalar-only views, a plain object type is enough:
|
|
72
81
|
|
|
73
82
|
```ts
|
|
74
|
-
|
|
75
|
-
IndustrialModel,
|
|
76
|
-
ModelProps,
|
|
77
|
-
ModelRelations,
|
|
78
|
-
NodeId,
|
|
79
|
-
QueryResultItem,
|
|
80
|
-
} from "industrial-model";
|
|
81
|
-
|
|
82
|
-
type CogniteAssetClass = IndustrialModel<{
|
|
83
|
+
type CogniteAssetClass = {
|
|
83
84
|
name: string;
|
|
84
85
|
code: string;
|
|
85
|
-
}
|
|
86
|
+
};
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
When a view has expandable relations, use `IndustrialModel<TProps, TRelations>`. Put the raw view properties in `TProps`, and put expandable relation result shapes in `TRelations`.
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import type { IndustrialModel, ModelProps, ModelRelations, NodeId } from "industrial-model";
|
|
86
93
|
|
|
87
94
|
type CogniteAsset = IndustrialModel<
|
|
88
95
|
{
|
|
89
96
|
name: string;
|
|
90
97
|
description: string;
|
|
91
98
|
tags: string[];
|
|
92
|
-
aliases: string[];
|
|
93
99
|
sourceId: string;
|
|
94
|
-
sourceCreatedTime: string;
|
|
95
|
-
sourceUpdatedTime: string;
|
|
96
100
|
parent?: NodeId;
|
|
97
101
|
root?: NodeId;
|
|
98
102
|
path: NodeId[];
|
|
99
103
|
assetClass?: NodeId;
|
|
100
|
-
type?: NodeId;
|
|
101
|
-
source?: NodeId;
|
|
102
104
|
},
|
|
103
105
|
{
|
|
104
106
|
parent?: CogniteAsset;
|
|
@@ -108,77 +110,27 @@ type CogniteAsset = IndustrialModel<
|
|
|
108
110
|
}
|
|
109
111
|
>;
|
|
110
112
|
|
|
111
|
-
type CogniteActivity = IndustrialModel<{
|
|
112
|
-
name: string;
|
|
113
|
-
description: string;
|
|
114
|
-
startTime: string;
|
|
115
|
-
endTime: string;
|
|
116
|
-
scheduledStartTime: string;
|
|
117
|
-
scheduledEndTime: string;
|
|
118
|
-
assets: NodeId[];
|
|
119
|
-
equipment: NodeId[];
|
|
120
|
-
timeSeries: NodeId[];
|
|
121
|
-
}>;
|
|
122
|
-
|
|
123
113
|
type CogniteEquipment = IndustrialModel<
|
|
124
114
|
{
|
|
125
115
|
name: string;
|
|
126
|
-
description: string;
|
|
127
116
|
manufacturer: string;
|
|
128
117
|
serialNumber: string;
|
|
129
118
|
tags: string[];
|
|
130
119
|
asset?: NodeId;
|
|
131
|
-
equipmentType?: NodeId;
|
|
132
|
-
source?: NodeId;
|
|
133
120
|
},
|
|
134
121
|
{
|
|
135
122
|
asset?: CogniteAsset;
|
|
136
|
-
activities?: CogniteActivity[];
|
|
137
|
-
}
|
|
138
|
-
>;
|
|
139
|
-
|
|
140
|
-
type CogniteUnit = IndustrialModel<{
|
|
141
|
-
name: string;
|
|
142
|
-
symbol: string;
|
|
143
|
-
quantity: string;
|
|
144
|
-
source: string;
|
|
145
|
-
}>;
|
|
146
|
-
|
|
147
|
-
type CogniteTimeSeries = IndustrialModel<
|
|
148
|
-
{
|
|
149
|
-
name: string;
|
|
150
|
-
description: string;
|
|
151
|
-
isStep: boolean;
|
|
152
|
-
sourceUnit: string;
|
|
153
|
-
unit?: NodeId;
|
|
154
|
-
assets: NodeId[];
|
|
155
|
-
equipment: NodeId[];
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
unit?: CogniteUnit;
|
|
159
|
-
}
|
|
160
|
-
>;
|
|
161
|
-
|
|
162
|
-
type Cognite360Image = IndustrialModel<{
|
|
163
|
-
takenAt: string;
|
|
164
|
-
}>;
|
|
165
|
-
|
|
166
|
-
type Cognite3DObject = IndustrialModel<
|
|
167
|
-
{
|
|
168
|
-
name: string;
|
|
169
|
-
description: string;
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
images360?: Cognite360Image[];
|
|
173
123
|
}
|
|
174
124
|
>;
|
|
175
125
|
```
|
|
176
126
|
|
|
177
|
-
|
|
127
|
+
The relation metadata is type-only. It lets the SDK infer nested `select` trees and nested filters while Cognite remains the source of truth for the actual view and relation definitions.
|
|
128
|
+
|
|
129
|
+
All examples below use the [Cognite Core Data Model](https://docs.cognite.com/cdf/data_modeling/reference_data_models/cognite_core/), space `cdf_cdm`, version `v1`.
|
|
178
130
|
|
|
179
|
-
|
|
131
|
+
## Query Basics
|
|
180
132
|
|
|
181
|
-
|
|
133
|
+
Start with a single view, select the fields the application needs, then layer on filters and sorting.
|
|
182
134
|
|
|
183
135
|
```ts
|
|
184
136
|
const { items, cursor } = await model.query<CogniteAsset>()({
|
|
@@ -192,32 +144,22 @@ const { items, cursor } = await model.query<CogniteAsset>()({
|
|
|
192
144
|
filters: {
|
|
193
145
|
name: { prefix: "Pump" },
|
|
194
146
|
},
|
|
195
|
-
sort: {
|
|
147
|
+
sort: {
|
|
148
|
+
name: "ascending",
|
|
149
|
+
},
|
|
196
150
|
limit: 100,
|
|
197
151
|
});
|
|
198
152
|
```
|
|
199
153
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
### Query a single asset by externalId
|
|
154
|
+
The returned item type follows the selection:
|
|
203
155
|
|
|
204
156
|
```ts
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
filters: {
|
|
209
|
-
externalId: { eq: "WMT:VAL" },
|
|
210
|
-
},
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
const asset = items[0];
|
|
157
|
+
items[0]?.name; // string
|
|
158
|
+
items[0]?.description; // string
|
|
159
|
+
items[0]?.externalId; // instance metadata is always included
|
|
214
160
|
```
|
|
215
161
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
### Query assets with parent and root relations
|
|
219
|
-
|
|
220
|
-
Traverse up the asset hierarchy — fetch each asset alongside its direct parent and the root of the tree.
|
|
162
|
+
To find one known instance, filter by `externalId`:
|
|
221
163
|
|
|
222
164
|
```ts
|
|
223
165
|
const { items } = await model.query<CogniteAsset>()({
|
|
@@ -225,51 +167,31 @@ const { items } = await model.query<CogniteAsset>()({
|
|
|
225
167
|
select: {
|
|
226
168
|
name: true,
|
|
227
169
|
description: true,
|
|
228
|
-
|
|
229
|
-
name: true,
|
|
230
|
-
description: true,
|
|
231
|
-
parent: {
|
|
232
|
-
name: true,
|
|
233
|
-
},
|
|
234
|
-
},
|
|
235
|
-
root: {
|
|
236
|
-
name: true,
|
|
237
|
-
},
|
|
170
|
+
tags: true,
|
|
238
171
|
},
|
|
239
172
|
filters: {
|
|
240
|
-
|
|
173
|
+
externalId: { eq: "WMT:VAL" },
|
|
241
174
|
},
|
|
242
|
-
limit: 50,
|
|
243
175
|
});
|
|
244
176
|
|
|
245
|
-
const
|
|
177
|
+
const asset = items[0];
|
|
246
178
|
```
|
|
247
179
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
### Query assets with their full path
|
|
251
|
-
|
|
252
|
-
The `path` property is a list of `NodeId` references representing the ancestor chain. Use it to reconstruct breadcrumbs.
|
|
180
|
+
Use `_all` when you want every scalar property from the root view:
|
|
253
181
|
|
|
254
182
|
```ts
|
|
255
183
|
const { items } = await model.query<CogniteAsset>()({
|
|
256
184
|
viewExternalId: "CogniteAsset",
|
|
257
|
-
select: {
|
|
258
|
-
|
|
259
|
-
path: {
|
|
260
|
-
name: true,
|
|
261
|
-
description: true,
|
|
262
|
-
},
|
|
263
|
-
},
|
|
264
|
-
filters: {
|
|
265
|
-
externalId: { eq: "WMT:VAL" },
|
|
266
|
-
},
|
|
185
|
+
select: { _all: true },
|
|
186
|
+
limit: 50,
|
|
267
187
|
});
|
|
268
188
|
```
|
|
269
189
|
|
|
270
|
-
|
|
190
|
+
`_all` includes scalar fields and relation IDs. Add nested selections when you want relation objects instead of `NodeId` references.
|
|
191
|
+
|
|
192
|
+
## Filters And Sorting
|
|
271
193
|
|
|
272
|
-
|
|
194
|
+
Filters are typed from your model. String, number, boolean, date, `NodeId`, and list fields each expose the operators that make sense for that field.
|
|
273
195
|
|
|
274
196
|
```ts
|
|
275
197
|
const { items } = await model.query<CogniteEquipment>()({
|
|
@@ -285,249 +207,157 @@ const { items } = await model.query<CogniteEquipment>()({
|
|
|
285
207
|
asset: { eq: { space: "my-space", externalId: "WMT:VAL" } },
|
|
286
208
|
manufacturer: { exists: true },
|
|
287
209
|
},
|
|
288
|
-
sort: {
|
|
210
|
+
sort: {
|
|
211
|
+
name: "ascending",
|
|
212
|
+
},
|
|
289
213
|
limit: 50,
|
|
290
214
|
});
|
|
291
215
|
```
|
|
292
216
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
### Query time series with their unit
|
|
217
|
+
Combine conditions with `AND`, `OR`, and `NOT`:
|
|
296
218
|
|
|
297
219
|
```ts
|
|
298
|
-
const { items } = await model.query<
|
|
299
|
-
viewExternalId: "
|
|
220
|
+
const { items } = await model.query<CogniteAsset>()({
|
|
221
|
+
viewExternalId: "CogniteAsset",
|
|
300
222
|
select: {
|
|
301
223
|
name: true,
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
sourceUnit: true,
|
|
305
|
-
unit: {
|
|
306
|
-
name: true,
|
|
307
|
-
symbol: true,
|
|
308
|
-
quantity: true,
|
|
309
|
-
},
|
|
224
|
+
tags: true,
|
|
225
|
+
sourceId: true,
|
|
310
226
|
},
|
|
311
227
|
filters: {
|
|
312
|
-
|
|
313
|
-
|
|
228
|
+
OR: [
|
|
229
|
+
{ tags: { containsAny: ["critical"] } },
|
|
230
|
+
{ name: { prefix: "Compressor" } },
|
|
231
|
+
],
|
|
232
|
+
NOT: {
|
|
233
|
+
sourceId: { eq: "legacy-system" },
|
|
234
|
+
},
|
|
314
235
|
},
|
|
315
|
-
limit:
|
|
236
|
+
limit: 100,
|
|
316
237
|
});
|
|
317
238
|
```
|
|
318
239
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
### Query activities in a time window
|
|
240
|
+
List fields support `containsAny` and `containsAll`:
|
|
322
241
|
|
|
323
242
|
```ts
|
|
324
|
-
const
|
|
325
|
-
viewExternalId: "
|
|
243
|
+
const critical = await model.query<CogniteAsset>()({
|
|
244
|
+
viewExternalId: "CogniteAsset",
|
|
326
245
|
select: {
|
|
327
246
|
name: true,
|
|
328
|
-
|
|
329
|
-
startTime: true,
|
|
330
|
-
endTime: true,
|
|
331
|
-
scheduledStartTime: true,
|
|
332
|
-
scheduledEndTime: true,
|
|
247
|
+
tags: true,
|
|
333
248
|
},
|
|
334
249
|
filters: {
|
|
335
|
-
|
|
250
|
+
tags: { containsAny: ["critical", "safety"] },
|
|
336
251
|
},
|
|
337
|
-
|
|
338
|
-
limit: 500,
|
|
252
|
+
limit: 100,
|
|
339
253
|
});
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
---
|
|
343
254
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
Fetch assets that are either tagged `"critical"` or have a name starting with `"Compressor"`, but exclude those from source `"legacy-system"`.
|
|
347
|
-
|
|
348
|
-
```ts
|
|
349
|
-
const { items } = await model.query<CogniteAsset>()({
|
|
255
|
+
const fullyTagged = await model.query<CogniteAsset>()({
|
|
350
256
|
viewExternalId: "CogniteAsset",
|
|
351
|
-
select: {
|
|
257
|
+
select: {
|
|
258
|
+
name: true,
|
|
259
|
+
tags: true,
|
|
260
|
+
},
|
|
352
261
|
filters: {
|
|
353
|
-
|
|
354
|
-
{ tags: { containsAny: ["critical"] } },
|
|
355
|
-
{ name: { prefix: "Compressor" } },
|
|
356
|
-
],
|
|
357
|
-
NOT: { sourceId: { eq: "legacy-system" } },
|
|
262
|
+
tags: { containsAll: ["production", "verified"] },
|
|
358
263
|
},
|
|
359
264
|
limit: 100,
|
|
360
265
|
});
|
|
361
266
|
```
|
|
362
267
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
### Paginate through all assets
|
|
366
|
-
|
|
367
|
-
```ts
|
|
368
|
-
let cursor: string | null = null;
|
|
369
|
-
const allAssets: QueryResultItem<CogniteAsset, { name: true; description: true }>[] = [];
|
|
370
|
-
|
|
371
|
-
do {
|
|
372
|
-
const result = await model.query<CogniteAsset>()({
|
|
373
|
-
viewExternalId: "CogniteAsset",
|
|
374
|
-
select: { name: true, description: true },
|
|
375
|
-
limit: 1000,
|
|
376
|
-
cursor,
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
allAssets.push(...result.items);
|
|
380
|
-
cursor = result.cursor;
|
|
381
|
-
} while (cursor !== null);
|
|
382
|
-
|
|
383
|
-
console.log(`Total assets: ${allAssets.length}`);
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
---
|
|
387
|
-
|
|
388
|
-
### Fetch all pages automatically
|
|
389
|
-
|
|
390
|
-
Pass `limit: -1` to follow root-view cursors until every page is loaded. The SDK issues multiple `instances.query` calls (1000 items per page by default). The returned `cursor` is always `null`.
|
|
268
|
+
Sort clauses apply to primitive fields on the root view, including node metadata such as `externalId`.
|
|
391
269
|
|
|
392
270
|
```ts
|
|
393
271
|
const { items } = await model.query<CogniteAsset>()({
|
|
394
272
|
viewExternalId: "CogniteAsset",
|
|
395
|
-
select: {
|
|
396
|
-
|
|
397
|
-
|
|
273
|
+
select: {
|
|
274
|
+
name: true,
|
|
275
|
+
sourceId: true,
|
|
276
|
+
},
|
|
277
|
+
sort: {
|
|
278
|
+
name: "ascending",
|
|
279
|
+
externalId: "descending",
|
|
280
|
+
},
|
|
281
|
+
limit: 100,
|
|
398
282
|
});
|
|
399
|
-
|
|
400
|
-
console.log(`Loaded ${items.length} assets across all pages`);
|
|
401
283
|
```
|
|
402
284
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
### Select all scalar fields
|
|
406
|
-
|
|
407
|
-
Use `_all` to include every scalar property on the view without listing them individually. Relation fields are returned as `NodeId` references but are not expanded — add nested `select` blocks when you need related data.
|
|
408
|
-
|
|
409
|
-
```ts
|
|
410
|
-
const { items } = await model.query<CogniteAsset>()({
|
|
411
|
-
viewExternalId: "CogniteAsset",
|
|
412
|
-
select: { _all: true },
|
|
413
|
-
limit: 50,
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
// items[0] includes name, description, tags, parent (as NodeId), etc.
|
|
417
|
-
```
|
|
285
|
+
## Text Search
|
|
418
286
|
|
|
419
|
-
|
|
287
|
+
Use `search` on Cognite text properties and string-list text properties when you want full-text matching instead of exact or prefix matching. The optional `operator` is passed to Cognite search and defaults to `"OR"`.
|
|
420
288
|
|
|
421
289
|
```ts
|
|
422
290
|
const { items } = await model.query<CogniteAsset>()({
|
|
423
291
|
viewExternalId: "CogniteAsset",
|
|
424
292
|
select: {
|
|
425
|
-
|
|
426
|
-
|
|
293
|
+
name: true,
|
|
294
|
+
description: true,
|
|
295
|
+
tags: true,
|
|
427
296
|
},
|
|
428
|
-
|
|
297
|
+
filters: {
|
|
298
|
+
name: { search: { query: "root pump", operator: "AND" } },
|
|
299
|
+
tags: { search: { query: "critical" } },
|
|
300
|
+
},
|
|
301
|
+
limit: 100,
|
|
429
302
|
});
|
|
430
303
|
```
|
|
431
304
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
### Filter by multiple external IDs
|
|
305
|
+
Search filters can be combined with regular operators. The SDK first calls Cognite `instances.search`, maps the matched nodes to instance references, and then applies those references to the query or aggregate request.
|
|
435
306
|
|
|
436
307
|
```ts
|
|
437
|
-
const
|
|
308
|
+
const pumps = await model.query<CogniteAsset>()({
|
|
438
309
|
viewExternalId: "CogniteAsset",
|
|
439
|
-
select: {
|
|
310
|
+
select: {
|
|
311
|
+
name: true,
|
|
312
|
+
sourceId: true,
|
|
313
|
+
},
|
|
440
314
|
filters: {
|
|
441
|
-
|
|
442
|
-
|
|
315
|
+
name: {
|
|
316
|
+
prefix: "Pump",
|
|
317
|
+
search: { query: "motor" },
|
|
443
318
|
},
|
|
319
|
+
sourceId: { exists: true },
|
|
444
320
|
},
|
|
445
321
|
});
|
|
446
322
|
```
|
|
447
323
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
### Filter assets by tags
|
|
451
|
-
|
|
452
|
-
```ts
|
|
453
|
-
// Match assets that have at least one of these tags
|
|
454
|
-
const critical = await model.query<CogniteAsset>()({
|
|
455
|
-
viewExternalId: "CogniteAsset",
|
|
456
|
-
select: { name: true, tags: true },
|
|
457
|
-
filters: { tags: { containsAny: ["critical", "safety"] } },
|
|
458
|
-
limit: 100,
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
// Match assets that must have every tag
|
|
462
|
-
const fullyTagged = await model.query<CogniteAsset>()({
|
|
463
|
-
viewExternalId: "CogniteAsset",
|
|
464
|
-
select: { name: true, tags: true },
|
|
465
|
-
filters: { tags: { containsAll: ["production", "verified"] } },
|
|
466
|
-
limit: 100,
|
|
467
|
-
});
|
|
468
|
-
```
|
|
469
|
-
|
|
470
|
-
---
|
|
324
|
+
## Relations
|
|
471
325
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
Filter the root view based on properties of a direct or nested relation. This uses Cognite nested filters under the hood.
|
|
326
|
+
The same `select` object that selects scalar fields can expand relations. Direct relations move outward from the current node.
|
|
475
327
|
|
|
476
328
|
```ts
|
|
477
|
-
// Assets whose parent is named "Site Root"
|
|
478
329
|
const { items } = await model.query<CogniteAsset>()({
|
|
479
|
-
viewExternalId: "CogniteAsset",
|
|
480
|
-
select: { name: true, parent: { name: true } },
|
|
481
|
-
filters: {
|
|
482
|
-
parent: { name: { eq: "Site Root" } },
|
|
483
|
-
},
|
|
484
|
-
limit: 50,
|
|
485
|
-
});
|
|
486
|
-
|
|
487
|
-
// Assets whose parent's asset class code is "PUMP"
|
|
488
|
-
const pumpsByClass = await model.query<CogniteAsset>()({
|
|
489
330
|
viewExternalId: "CogniteAsset",
|
|
490
331
|
select: {
|
|
491
332
|
name: true,
|
|
492
|
-
parent: {
|
|
333
|
+
parent: {
|
|
334
|
+
name: true,
|
|
335
|
+
description: true,
|
|
336
|
+
parent: {
|
|
337
|
+
name: true,
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
root: {
|
|
341
|
+
name: true,
|
|
342
|
+
},
|
|
493
343
|
},
|
|
494
344
|
filters: {
|
|
495
|
-
|
|
345
|
+
name: { prefix: "Pump" },
|
|
496
346
|
},
|
|
497
347
|
limit: 50,
|
|
498
348
|
});
|
|
499
349
|
|
|
500
|
-
|
|
501
|
-
const filtered = await model.query<CogniteAsset>()({
|
|
502
|
-
viewExternalId: "CogniteAsset",
|
|
503
|
-
select: { name: true, parent: { name: true } },
|
|
504
|
-
filters: {
|
|
505
|
-
AND: [
|
|
506
|
-
{ name: { prefix: "Pump" } },
|
|
507
|
-
{ parent: { name: { exists: true } } },
|
|
508
|
-
],
|
|
509
|
-
},
|
|
510
|
-
limit: 100,
|
|
511
|
-
});
|
|
350
|
+
const firstParentName = items[0]?.parent?.name;
|
|
512
351
|
```
|
|
513
352
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
### Query child assets (reverse relation)
|
|
517
|
-
|
|
518
|
-
Declare reverse relations in the `IndustrialModel<TProps, TRelations>` metadata. The library resolves the correct traversal direction from your data model.
|
|
353
|
+
List relations work the same way. For example, `path` can be expanded into asset objects for breadcrumb-style views.
|
|
519
354
|
|
|
520
355
|
```ts
|
|
521
|
-
|
|
522
|
-
ModelProps<CogniteAsset>,
|
|
523
|
-
ModelRelations<CogniteAsset> & { children?: CogniteAsset[] }
|
|
524
|
-
>;
|
|
525
|
-
|
|
526
|
-
const { items } = await model.query<AssetWithChildren>()({
|
|
356
|
+
const { items } = await model.query<CogniteAsset>()({
|
|
527
357
|
viewExternalId: "CogniteAsset",
|
|
528
358
|
select: {
|
|
529
359
|
name: true,
|
|
530
|
-
|
|
360
|
+
path: {
|
|
531
361
|
name: true,
|
|
532
362
|
description: true,
|
|
533
363
|
},
|
|
@@ -538,140 +368,174 @@ const { items } = await model.query<AssetWithChildren>()({
|
|
|
538
368
|
});
|
|
539
369
|
```
|
|
540
370
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
### Traverse edge relations (360 images on 3D objects)
|
|
544
|
-
|
|
545
|
-
Some relations are modeled as edges rather than direct node links. Select them the same way — the SDK builds the edge hop automatically.
|
|
371
|
+
Nested relation filters let you filter the root view based on related nodes.
|
|
546
372
|
|
|
547
373
|
```ts
|
|
548
|
-
const { items } = await model.query<
|
|
549
|
-
viewExternalId: "
|
|
374
|
+
const { items } = await model.query<CogniteAsset>()({
|
|
375
|
+
viewExternalId: "CogniteAsset",
|
|
550
376
|
select: {
|
|
551
377
|
name: true,
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
name: { prefix: "Tank" },
|
|
378
|
+
parent: {
|
|
379
|
+
name: true,
|
|
380
|
+
},
|
|
556
381
|
},
|
|
557
|
-
|
|
382
|
+
filters: {
|
|
383
|
+
parent: {
|
|
384
|
+
name: { eq: "Site Root" },
|
|
385
|
+
},
|
|
386
|
+
},
|
|
387
|
+
limit: 50,
|
|
558
388
|
});
|
|
559
389
|
```
|
|
560
390
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
### Sort by multiple fields
|
|
564
|
-
|
|
565
|
-
Sort clauses apply to primitive fields on the root view, including node-level properties like `externalId`.
|
|
391
|
+
You can keep moving through the graph:
|
|
566
392
|
|
|
567
393
|
```ts
|
|
568
|
-
const
|
|
394
|
+
const pumpsByClass = await model.query<CogniteAsset>()({
|
|
569
395
|
viewExternalId: "CogniteAsset",
|
|
570
|
-
select: {
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
396
|
+
select: {
|
|
397
|
+
name: true,
|
|
398
|
+
parent: {
|
|
399
|
+
assetClass: {
|
|
400
|
+
name: true,
|
|
401
|
+
code: true,
|
|
402
|
+
},
|
|
403
|
+
},
|
|
574
404
|
},
|
|
575
|
-
|
|
405
|
+
filters: {
|
|
406
|
+
parent: {
|
|
407
|
+
assetClass: {
|
|
408
|
+
code: { eq: "PUMP" },
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
limit: 50,
|
|
576
413
|
});
|
|
577
414
|
```
|
|
578
415
|
|
|
579
|
-
|
|
416
|
+
### Reverse Relations
|
|
580
417
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
Point the client at any FDM in your project — not only Cognite Core. Scalar fields work with a plain object type; use `IndustrialModel<TProps, TRelations>` when you need relation selects, filters, or inference.
|
|
418
|
+
Declare reverse relations in `IndustrialModel<TProps, TRelations>`. The SDK resolves the traversal direction from the Cognite data model.
|
|
584
419
|
|
|
585
420
|
```ts
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
type PlantArea = IndustrialModel<{
|
|
593
|
-
name: string;
|
|
594
|
-
code: string;
|
|
595
|
-
site?: NodeId;
|
|
596
|
-
}>;
|
|
421
|
+
type AssetWithChildren = IndustrialModel<
|
|
422
|
+
ModelProps<CogniteAsset>,
|
|
423
|
+
ModelRelations<CogniteAsset> & {
|
|
424
|
+
children?: CogniteAsset[];
|
|
425
|
+
}
|
|
426
|
+
>;
|
|
597
427
|
|
|
598
|
-
const { items } = await model.query<
|
|
599
|
-
viewExternalId: "
|
|
600
|
-
select: {
|
|
601
|
-
|
|
602
|
-
|
|
428
|
+
const { items } = await model.query<AssetWithChildren>()({
|
|
429
|
+
viewExternalId: "CogniteAsset",
|
|
430
|
+
select: {
|
|
431
|
+
name: true,
|
|
432
|
+
children: {
|
|
433
|
+
name: true,
|
|
434
|
+
description: true,
|
|
435
|
+
},
|
|
436
|
+
},
|
|
437
|
+
filters: {
|
|
438
|
+
externalId: { eq: "WMT:VAL" },
|
|
439
|
+
},
|
|
603
440
|
});
|
|
604
441
|
```
|
|
605
442
|
|
|
606
|
-
|
|
443
|
+
### Edge Relations
|
|
607
444
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
A single query combining nested selects, nested filters, sorting, and pagination.
|
|
445
|
+
Some relations are modeled as edges rather than direct node references. Select them with the same relation syntax.
|
|
611
446
|
|
|
612
447
|
```ts
|
|
613
|
-
type
|
|
614
|
-
|
|
615
|
-
|
|
448
|
+
type Cognite360Image = IndustrialModel<{
|
|
449
|
+
takenAt: string;
|
|
450
|
+
}>;
|
|
451
|
+
|
|
452
|
+
type Cognite3DObject = IndustrialModel<
|
|
453
|
+
{
|
|
454
|
+
name: string;
|
|
455
|
+
description: string;
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
images360?: Cognite360Image[];
|
|
459
|
+
}
|
|
616
460
|
>;
|
|
617
461
|
|
|
618
|
-
const { items
|
|
619
|
-
viewExternalId: "
|
|
462
|
+
const { items } = await model.query<Cognite3DObject>()({
|
|
463
|
+
viewExternalId: "Cognite3DObject",
|
|
620
464
|
select: {
|
|
621
465
|
name: true,
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
parent: {
|
|
625
|
-
name: true,
|
|
626
|
-
assetClass: { name: true, code: true },
|
|
466
|
+
images360: {
|
|
467
|
+
takenAt: true,
|
|
627
468
|
},
|
|
628
469
|
},
|
|
629
470
|
filters: {
|
|
630
|
-
name: { prefix: "
|
|
631
|
-
parent: { name: { exists: true } },
|
|
632
|
-
OR: [
|
|
633
|
-
{ tags: { containsAny: ["critical"] } },
|
|
634
|
-
{ sourceId: { eq: "sap" } },
|
|
635
|
-
],
|
|
471
|
+
name: { prefix: "Tank" },
|
|
636
472
|
},
|
|
637
|
-
|
|
638
|
-
limit: 25,
|
|
639
|
-
cursor: null,
|
|
473
|
+
limit: 20,
|
|
640
474
|
});
|
|
475
|
+
```
|
|
641
476
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
477
|
+
## Pagination
|
|
478
|
+
|
|
479
|
+
`query()` returns a root cursor when more root-view items are available.
|
|
480
|
+
|
|
481
|
+
```ts
|
|
482
|
+
import type { QueryResultItem } from "industrial-model";
|
|
483
|
+
|
|
484
|
+
let cursor: string | null = null;
|
|
485
|
+
const allAssets: QueryResultItem<CogniteAsset, { name: true; description: true }>[] = [];
|
|
486
|
+
|
|
487
|
+
do {
|
|
488
|
+
const result = await model.query<CogniteAsset>()({
|
|
645
489
|
viewExternalId: "CogniteAsset",
|
|
646
490
|
select: {
|
|
647
491
|
name: true,
|
|
648
492
|
description: true,
|
|
649
|
-
tags: true,
|
|
650
|
-
parent: { name: true, assetClass: { name: true, code: true } },
|
|
651
|
-
},
|
|
652
|
-
filters: {
|
|
653
|
-
name: { prefix: "WMT" },
|
|
654
|
-
parent: { name: { exists: true } },
|
|
655
493
|
},
|
|
656
|
-
|
|
657
|
-
limit: 25,
|
|
494
|
+
limit: 1000,
|
|
658
495
|
cursor,
|
|
659
496
|
});
|
|
660
|
-
|
|
497
|
+
|
|
498
|
+
allAssets.push(...result.items);
|
|
499
|
+
cursor = result.cursor;
|
|
500
|
+
} while (cursor !== null);
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
Pass `limit: -1` when you want the SDK to follow all root cursors automatically. The SDK issues multiple `instances.query` calls, using 1000 root items per page by default, and returns `cursor: null`.
|
|
504
|
+
|
|
505
|
+
```ts
|
|
506
|
+
const { items } = await model.query<CogniteAsset>()({
|
|
507
|
+
viewExternalId: "CogniteAsset",
|
|
508
|
+
select: {
|
|
509
|
+
name: true,
|
|
510
|
+
description: true,
|
|
511
|
+
},
|
|
512
|
+
filters: {
|
|
513
|
+
tags: { containsAny: ["production"] },
|
|
514
|
+
},
|
|
515
|
+
limit: -1,
|
|
516
|
+
});
|
|
661
517
|
```
|
|
662
518
|
|
|
663
|
-
|
|
519
|
+
Expanded relations use internal pagination as well. When a nested relation query reaches the internal page size, the client follows dependency cursors for up to 3 additional rounds.
|
|
664
520
|
|
|
665
|
-
|
|
521
|
+
## Aggregation
|
|
666
522
|
|
|
667
|
-
|
|
523
|
+
Use `aggregate()` when you need grouped counts, distinct values, or numeric summaries without loading every instance.
|
|
524
|
+
|
|
525
|
+
Group and count assets by `sourceId`:
|
|
668
526
|
|
|
669
527
|
```ts
|
|
670
528
|
const { items } = await model.aggregate<CogniteAsset>()({
|
|
671
529
|
viewExternalId: "CogniteAsset",
|
|
672
|
-
groupBy: {
|
|
673
|
-
|
|
674
|
-
|
|
530
|
+
groupBy: {
|
|
531
|
+
sourceId: true,
|
|
532
|
+
},
|
|
533
|
+
aggregate: {
|
|
534
|
+
count: {},
|
|
535
|
+
},
|
|
536
|
+
filters: {
|
|
537
|
+
name: { prefix: "WMT" },
|
|
538
|
+
},
|
|
675
539
|
});
|
|
676
540
|
|
|
677
541
|
for (const row of items) {
|
|
@@ -679,37 +543,36 @@ for (const row of items) {
|
|
|
679
543
|
}
|
|
680
544
|
```
|
|
681
545
|
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
### List distinct source IDs
|
|
685
|
-
|
|
686
|
-
Omit `aggregate` to return unique combinations of the `groupBy` fields (up to 1000 groups).
|
|
546
|
+
Omit `aggregate` to list distinct values for grouped fields:
|
|
687
547
|
|
|
688
548
|
```ts
|
|
689
549
|
const { items } = await model.aggregate<CogniteAsset>()({
|
|
690
550
|
viewExternalId: "CogniteAsset",
|
|
691
|
-
groupBy: {
|
|
551
|
+
groupBy: {
|
|
552
|
+
sourceId: true,
|
|
553
|
+
},
|
|
692
554
|
});
|
|
693
555
|
|
|
694
556
|
const sourceIds = items.map((row) => row.group?.sourceId);
|
|
695
557
|
```
|
|
696
558
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
### Average volume by type
|
|
700
|
-
|
|
701
|
-
Use `avg`, `min`, `max`, or `sum` on numeric view properties. Only one aggregate operation per call.
|
|
559
|
+
Use `avg`, `min`, `max`, or `sum` on numeric properties:
|
|
702
560
|
|
|
703
561
|
```ts
|
|
704
562
|
type PointCloudVolume = IndustrialModel<{
|
|
705
563
|
volume: number;
|
|
706
564
|
volumeType: string;
|
|
565
|
+
object3D?: NodeId;
|
|
707
566
|
}>;
|
|
708
567
|
|
|
709
568
|
const { items } = await model.aggregate<PointCloudVolume>()({
|
|
710
569
|
viewExternalId: "CognitePointCloudVolume",
|
|
711
|
-
groupBy: {
|
|
712
|
-
|
|
570
|
+
groupBy: {
|
|
571
|
+
volumeType: true,
|
|
572
|
+
},
|
|
573
|
+
aggregate: {
|
|
574
|
+
avg: "volume",
|
|
575
|
+
},
|
|
713
576
|
});
|
|
714
577
|
|
|
715
578
|
items[0]?.group?.volumeType;
|
|
@@ -717,216 +580,387 @@ items[0]?.aggregate?.property; // "volume"
|
|
|
717
580
|
items[0]?.aggregate?.value;
|
|
718
581
|
```
|
|
719
582
|
|
|
720
|
-
|
|
583
|
+
Count all rows matching a filter:
|
|
721
584
|
|
|
722
585
|
```ts
|
|
723
|
-
await model.aggregate<
|
|
724
|
-
viewExternalId: "
|
|
725
|
-
aggregate: {
|
|
586
|
+
const { items } = await model.aggregate<CogniteAsset>()({
|
|
587
|
+
viewExternalId: "CogniteAsset",
|
|
588
|
+
aggregate: {
|
|
589
|
+
count: {},
|
|
590
|
+
},
|
|
591
|
+
filters: {
|
|
592
|
+
OR: [{ tags: { containsAny: ["critical"] } }, { sourceId: { eq: "sap" } }],
|
|
593
|
+
},
|
|
726
594
|
});
|
|
727
595
|
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
aggregate: { max: "volume" },
|
|
731
|
-
});
|
|
596
|
+
items[0]?.aggregate?.value;
|
|
597
|
+
```
|
|
732
598
|
|
|
733
|
-
|
|
599
|
+
Group by a direct relation when you need relation IDs in the result:
|
|
600
|
+
|
|
601
|
+
```ts
|
|
602
|
+
const { items } = await model.aggregate<PointCloudVolume>()({
|
|
734
603
|
viewExternalId: "CognitePointCloudVolume",
|
|
735
|
-
|
|
604
|
+
groupBy: {
|
|
605
|
+
object3D: true,
|
|
606
|
+
},
|
|
607
|
+
aggregate: {
|
|
608
|
+
sum: "volume",
|
|
609
|
+
},
|
|
736
610
|
});
|
|
737
|
-
```
|
|
738
611
|
|
|
739
|
-
|
|
612
|
+
items[0]?.group?.object3D?.externalId;
|
|
613
|
+
```
|
|
740
614
|
|
|
741
|
-
|
|
615
|
+
Text search filters are also supported in aggregations:
|
|
742
616
|
|
|
743
617
|
```ts
|
|
744
618
|
const { items } = await model.aggregate<CogniteAsset>()({
|
|
745
619
|
viewExternalId: "CogniteAsset",
|
|
746
|
-
aggregate: {
|
|
620
|
+
aggregate: {
|
|
621
|
+
count: {},
|
|
622
|
+
},
|
|
623
|
+
filters: {
|
|
624
|
+
name: { search: { query: "compressor seal" } },
|
|
625
|
+
},
|
|
747
626
|
});
|
|
748
|
-
|
|
749
|
-
items[0]?.aggregate?.property; // "name"
|
|
750
|
-
items[0]?.aggregate?.value;
|
|
751
627
|
```
|
|
752
628
|
|
|
753
|
-
|
|
629
|
+
## Runtime Validation
|
|
754
630
|
|
|
755
|
-
|
|
631
|
+
By default, the SDK validates query inputs against the loaded Cognite view metadata before building the request. Query results are mapped without parsing each returned item.
|
|
756
632
|
|
|
757
|
-
|
|
633
|
+
Enable `validateResults` when you also want result parsing through Zod schemas derived from Cognite view metadata:
|
|
758
634
|
|
|
759
635
|
```ts
|
|
760
|
-
const
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
636
|
+
const model = new IndustrialModelClient(
|
|
637
|
+
client,
|
|
638
|
+
{
|
|
639
|
+
space: "cdf_cdm",
|
|
640
|
+
externalId: "CogniteCore",
|
|
641
|
+
version: "v1",
|
|
765
642
|
},
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
643
|
+
{
|
|
644
|
+
validateResults: true,
|
|
645
|
+
},
|
|
646
|
+
);
|
|
769
647
|
```
|
|
770
648
|
|
|
771
|
-
|
|
649
|
+
When result validation is enabled, Cognite `date` and `timestamp` view properties are converted to JavaScript `Date` objects. Without it, result values are returned as Cognite provides them, usually ISO strings for timestamps.
|
|
772
650
|
|
|
773
|
-
|
|
651
|
+
## Cognite Core Client
|
|
774
652
|
|
|
775
|
-
|
|
653
|
+
For applications working with the Cognite Core Data Model (`cdf_cdm/CogniteCore/v1`), use `CogniteCoreClient` instead of `IndustrialModelClient`. It pre-configures the data model, bundles all view type definitions, and moves the view name to the first positional argument so TypeScript can infer the model type without a generic annotation.
|
|
776
654
|
|
|
777
655
|
```ts
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
object3D?: NodeId;
|
|
781
|
-
}>;
|
|
782
|
-
|
|
783
|
-
const { items } = await model.aggregate<PointCloudVolume>()({
|
|
784
|
-
viewExternalId: "CognitePointCloudVolume",
|
|
785
|
-
groupBy: { object3D: true },
|
|
786
|
-
aggregate: { sum: "volume" },
|
|
787
|
-
});
|
|
656
|
+
import { CogniteClient } from "@cognite/sdk";
|
|
657
|
+
import { CogniteCoreClient } from "industrial-model";
|
|
788
658
|
|
|
789
|
-
|
|
659
|
+
const client = new CogniteClient({ ... });
|
|
660
|
+
const core = new CogniteCoreClient(client);
|
|
790
661
|
```
|
|
791
662
|
|
|
792
|
-
|
|
663
|
+
Query any Cognite Core view by passing its name to `query()`:
|
|
793
664
|
|
|
794
|
-
|
|
665
|
+
```ts
|
|
666
|
+
const { items } = await core.query("CogniteAsset")({
|
|
667
|
+
select: {
|
|
668
|
+
name: true,
|
|
669
|
+
description: true,
|
|
670
|
+
parent: { name: true },
|
|
671
|
+
},
|
|
672
|
+
filters: {
|
|
673
|
+
name: { prefix: "Pump" },
|
|
674
|
+
},
|
|
675
|
+
limit: 50,
|
|
676
|
+
});
|
|
795
677
|
|
|
796
|
-
|
|
678
|
+
items[0]?.name; // string | undefined
|
|
679
|
+
items[0]?.parent?.name; // string | undefined
|
|
680
|
+
```
|
|
797
681
|
|
|
798
|
-
|
|
799
|
-
|--------|-------------|
|
|
800
|
-
| `IndustrialModelClient` | Main client |
|
|
801
|
-
| `IndustrialModel`, `ModelProps`, `ModelRelations` | Type helpers for models and relations |
|
|
802
|
-
| `NodeId`, `DataModelId` | Instance and data-model identifiers |
|
|
803
|
-
| `QueryOptions`, `QuerySelect`, `WhereInput`, `SortInput` | Query input types |
|
|
804
|
-
| `QueryResult`, `QueryResultItem`, `QueryResultMetadata` | Query output types |
|
|
805
|
-
| `AggregateOptions`, `AggregateGroupBy`, `AggregateDefinition` | Aggregate input types |
|
|
806
|
-
| `AggregateResult`, `AggregateResultItem`, `GroupByKey` | Aggregate output types |
|
|
807
|
-
| `buildViewSchema`, `nodeIdSchema` | Zod schemas built from Cognite view metadata |
|
|
808
|
-
| `SortDirection` | `"ascending"` \| `"descending"` |
|
|
682
|
+
The view name drives TypeScript inference — no generic annotation is needed. All filters, `select` fields, and nested relation selections are type-checked against the bundled view definition. Every feature available on `IndustrialModelClient` — text search, pagination, `limit: -1`, nested filters, and relation traversal — works identically.
|
|
809
683
|
|
|
810
|
-
|
|
684
|
+
Aggregations use the same positional-view-name pattern:
|
|
811
685
|
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
686
|
+
```ts
|
|
687
|
+
const { items } = await core.aggregate("CogniteEquipment")({
|
|
688
|
+
groupBy: { manufacturer: true },
|
|
689
|
+
aggregate: { count: {} },
|
|
690
|
+
filters: {
|
|
691
|
+
equipmentType: { exists: true },
|
|
692
|
+
},
|
|
693
|
+
});
|
|
817
694
|
|
|
818
|
-
|
|
695
|
+
items[0]?.group?.manufacturer;
|
|
696
|
+
items[0]?.aggregate?.value;
|
|
697
|
+
```
|
|
819
698
|
|
|
820
|
-
|
|
699
|
+
All Cognite Core view types are exported from `industrial-model` and can be imported directly for use with `IndustrialModelClient` if needed:
|
|
821
700
|
|
|
822
701
|
```ts
|
|
823
|
-
|
|
824
|
-
validateResults: true,
|
|
825
|
-
});
|
|
702
|
+
import type { CogniteAsset, CogniteEquipment, CogniteTimeSeries } from "industrial-model";
|
|
826
703
|
```
|
|
827
704
|
|
|
828
|
-
|
|
705
|
+
### Inward List-Relation Limitation
|
|
829
706
|
|
|
830
|
-
|
|
707
|
+
Cognite rejects server-side inward traversal of list direct relations. As a result, `timeSeries`, `files`, and `activities` cannot be expanded from `CogniteAsset`. Attempting to select them throws a descriptive error before the Cognite API is called, naming the view to query and the field to filter on.
|
|
831
708
|
|
|
832
|
-
|
|
833
|
-
|--------|------|-------------|
|
|
834
|
-
| `viewExternalId` | `string` | The view to query |
|
|
835
|
-
| `select` | `QuerySelect<TModel>` | Optional. Defaults to `{ _all: true }` (all scalar fields). Use `_all: true` explicitly or list fields; use nested objects for relations |
|
|
836
|
-
| `filters` | `WhereInput<TModel>` | Filter conditions (supports nested relation filters) |
|
|
837
|
-
| `sort` | `SortInput<TModel>` | Sort by primitive fields on the **root** view only |
|
|
838
|
-
| `limit` | `number` | Root page size (default `1000`). Use `-1` to fetch all root pages automatically |
|
|
839
|
-
| `cursor` | `string \| null` | Pagination cursor from a previous response |
|
|
709
|
+
The alternative is to query the target view directly and filter by the relation field pointing back to the asset:
|
|
840
710
|
|
|
841
|
-
|
|
711
|
+
```ts
|
|
712
|
+
// not supported — throws before calling Cognite
|
|
713
|
+
await core.query("CogniteAsset")({
|
|
714
|
+
select: { timeSeries: { name: true } } as never,
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
// correct alternative: query CogniteTimeSeries and filter by assets
|
|
718
|
+
const { items } = await core.query("CogniteTimeSeries")({
|
|
719
|
+
select: { name: true, type: true },
|
|
720
|
+
filters: {
|
|
721
|
+
assets: { containsAny: [{ space: "my-space", externalId: "WMT:VAL" }] },
|
|
722
|
+
},
|
|
723
|
+
});
|
|
724
|
+
```
|
|
842
725
|
|
|
843
|
-
|
|
726
|
+
## Custom Data Models
|
|
844
727
|
|
|
845
|
-
|
|
728
|
+
The client can query any FDM in your CDF project. Cognite Core is not required.
|
|
846
729
|
|
|
847
730
|
```ts
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
731
|
+
const model = new IndustrialModelClient(client, {
|
|
732
|
+
space: "my-custom-space",
|
|
733
|
+
externalId: "MyPlantModel",
|
|
734
|
+
version: "1",
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
type PlantArea = IndustrialModel<{
|
|
738
|
+
name: string;
|
|
739
|
+
code: string;
|
|
740
|
+
site?: NodeId;
|
|
741
|
+
}>;
|
|
742
|
+
|
|
743
|
+
const { items } = await model.query<PlantArea>()({
|
|
744
|
+
viewExternalId: "PlantArea",
|
|
745
|
+
select: {
|
|
746
|
+
name: true,
|
|
747
|
+
code: true,
|
|
748
|
+
site: true,
|
|
749
|
+
},
|
|
750
|
+
filters: {
|
|
751
|
+
code: { prefix: "AREA-" },
|
|
752
|
+
},
|
|
753
|
+
limit: 200,
|
|
754
|
+
});
|
|
852
755
|
```
|
|
853
756
|
|
|
854
|
-
|
|
757
|
+
## Complete Example
|
|
855
758
|
|
|
856
|
-
|
|
759
|
+
This example combines typed relations, nested selections, nested filters, sorting, and cursor pagination.
|
|
857
760
|
|
|
858
761
|
```ts
|
|
859
|
-
|
|
762
|
+
type AssetWithRelations = IndustrialModel<
|
|
763
|
+
ModelProps<CogniteAsset>,
|
|
764
|
+
ModelRelations<CogniteAsset> & {
|
|
765
|
+
children?: CogniteAsset[];
|
|
766
|
+
}
|
|
767
|
+
>;
|
|
768
|
+
|
|
769
|
+
const { items, cursor } = await model.query<AssetWithRelations>()({
|
|
860
770
|
viewExternalId: "CogniteAsset",
|
|
861
771
|
select: {
|
|
772
|
+
name: true,
|
|
773
|
+
description: true,
|
|
774
|
+
tags: true,
|
|
862
775
|
parent: {
|
|
863
776
|
name: true,
|
|
777
|
+
assetClass: {
|
|
778
|
+
name: true,
|
|
779
|
+
code: true,
|
|
780
|
+
},
|
|
781
|
+
},
|
|
782
|
+
children: {
|
|
783
|
+
name: true,
|
|
864
784
|
},
|
|
865
785
|
},
|
|
786
|
+
filters: {
|
|
787
|
+
name: { prefix: "WMT" },
|
|
788
|
+
parent: {
|
|
789
|
+
name: { exists: true },
|
|
790
|
+
},
|
|
791
|
+
OR: [
|
|
792
|
+
{ tags: { containsAny: ["critical"] } },
|
|
793
|
+
{ sourceId: { eq: "sap" } },
|
|
794
|
+
],
|
|
795
|
+
},
|
|
796
|
+
sort: {
|
|
797
|
+
name: "ascending",
|
|
798
|
+
},
|
|
799
|
+
limit: 25,
|
|
800
|
+
cursor: null,
|
|
866
801
|
});
|
|
867
802
|
|
|
868
|
-
|
|
869
|
-
|
|
803
|
+
if (cursor) {
|
|
804
|
+
const next = await model.query<AssetWithRelations>()({
|
|
805
|
+
viewExternalId: "CogniteAsset",
|
|
806
|
+
select: {
|
|
807
|
+
name: true,
|
|
808
|
+
description: true,
|
|
809
|
+
tags: true,
|
|
810
|
+
parent: {
|
|
811
|
+
name: true,
|
|
812
|
+
assetClass: {
|
|
813
|
+
name: true,
|
|
814
|
+
code: true,
|
|
815
|
+
},
|
|
816
|
+
},
|
|
817
|
+
},
|
|
818
|
+
filters: {
|
|
819
|
+
name: { prefix: "WMT" },
|
|
820
|
+
parent: {
|
|
821
|
+
name: { exists: true },
|
|
822
|
+
},
|
|
823
|
+
},
|
|
824
|
+
sort: {
|
|
825
|
+
name: "ascending",
|
|
826
|
+
},
|
|
827
|
+
limit: 25,
|
|
828
|
+
cursor,
|
|
829
|
+
});
|
|
830
|
+
}
|
|
870
831
|
```
|
|
871
832
|
|
|
872
|
-
|
|
833
|
+
## API Reference
|
|
873
834
|
|
|
874
|
-
|
|
875
|
-
|--------|------|-------------|
|
|
876
|
-
| `viewExternalId` | `string` | The view to aggregate |
|
|
877
|
-
| `groupBy` | `AggregateGroupBy<TModel>` | Optional. Object of groupable properties set to `true` (max 5) |
|
|
878
|
-
| `filters` | `WhereInput<TModel>` | Same filter syntax as `query` |
|
|
879
|
-
| `aggregate` | `AggregateDefinition<TModel>` | Optional. One of `avg`, `min`, `max`, `sum`, or `count` per call |
|
|
835
|
+
### `new CogniteCoreClient(client, options?)`
|
|
880
836
|
|
|
881
|
-
|
|
837
|
+
| Parameter | Type | Description |
|
|
838
|
+
| --- | --- | --- |
|
|
839
|
+
| `client` | `CogniteClient` | Authenticated Cognite SDK client. |
|
|
840
|
+
| `options` | `IndustrialModelClientOptions` | Optional. Same options as `IndustrialModelClient`. |
|
|
841
|
+
|
|
842
|
+
Pre-configured for the Cognite Core Data Model (`cdf_cdm/CogniteCore/v1`). The exported constant `COGNITE_CORE_DATA_MODEL` holds the data model identifier if you need to pass it to other utilities.
|
|
843
|
+
|
|
844
|
+
### `core.query(viewExternalId)(options)`
|
|
845
|
+
|
|
846
|
+
Same as `model.query<TModel>()(options)` on `IndustrialModelClient`, except the view is provided as the first positional argument and the model type is inferred from it. The `viewExternalId` option is not accepted in the second call. `viewExternalId` must be a valid `CogniteCoreViewExternalId`.
|
|
847
|
+
|
|
848
|
+
### `core.aggregate(viewExternalId)(options)`
|
|
849
|
+
|
|
850
|
+
Same as `model.aggregate<TModel>()(options)` on `IndustrialModelClient`, with the view name as the first positional argument.
|
|
851
|
+
|
|
852
|
+
### `new IndustrialModelClient(client, dataModelId, options?)`
|
|
853
|
+
|
|
854
|
+
| Parameter | Type | Description |
|
|
855
|
+
| --- | --- | --- |
|
|
856
|
+
| `client` | `CogniteClient` | Authenticated Cognite SDK client. |
|
|
857
|
+
| `dataModelId` | `DataModelId` | Data model `space`, `externalId`, and `version`. |
|
|
858
|
+
| `options.validateResults` | `boolean` | Optional. Parse result items with generated Zod schemas. |
|
|
882
859
|
|
|
883
|
-
|
|
860
|
+
On the first query or aggregation, view definitions are loaded from CDF and cached for the lifetime of the client instance.
|
|
861
|
+
|
|
862
|
+
### `model.query<TModel>()(options)`
|
|
863
|
+
|
|
864
|
+
`query()` uses a curried form so you can provide the model type first and still get return-type inference from `select`.
|
|
865
|
+
|
|
866
|
+
| Option | Description |
|
|
867
|
+
| --- | --- |
|
|
868
|
+
| `viewExternalId` | View to query. |
|
|
869
|
+
| `select` | Optional. Defaults to `{ _all: true }`. Use nested objects for relations. |
|
|
870
|
+
| `filters` | Field, logical, search, and nested relation filters. |
|
|
871
|
+
| `sort` | Sort by primitive fields on the root view only. |
|
|
872
|
+
| `limit` | Root page size. Defaults to `1000`. Use `-1` to fetch all root pages. |
|
|
873
|
+
| `cursor` | Root pagination cursor from a previous response. |
|
|
874
|
+
|
|
875
|
+
Returns:
|
|
884
876
|
|
|
885
877
|
```ts
|
|
886
|
-
type
|
|
887
|
-
|
|
888
|
-
|
|
878
|
+
type QueryResult<TItem> = {
|
|
879
|
+
items: TItem[];
|
|
880
|
+
cursor: string | null;
|
|
889
881
|
};
|
|
890
882
|
```
|
|
891
883
|
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
| Aggregate | Input | Use case |
|
|
895
|
-
|-----------|-------|----------|
|
|
896
|
-
| `count` | `{ count: {} }` | Row count (optionally filtered) |
|
|
897
|
-
| `count` | `{ count: "name" }` | Count non-null values for a property |
|
|
898
|
-
| `avg` | `{ avg: "volume" }` | Average of a numeric property |
|
|
899
|
-
| `min` | `{ min: "volume" }` | Minimum numeric value |
|
|
900
|
-
| `max` | `{ max: "volume" }` | Maximum numeric value |
|
|
901
|
-
| `sum` | `{ sum: "volume" }` | Sum of a numeric property |
|
|
902
|
-
|
|
903
|
-
See [Count assets by source ID](#count-assets-by-source-id), [List distinct source IDs](#list-distinct-source-ids), and [Average volume by type](#average-volume-by-type) for full examples.
|
|
884
|
+
Each item includes instance metadata such as `space`, `externalId`, `version`, `createdTime`, `deletedTime`, and `lastUpdatedTime`, plus the selected fields.
|
|
904
885
|
|
|
905
|
-
###
|
|
886
|
+
### `model.aggregate<TModel>()(options)`
|
|
906
887
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
888
|
+
| Option | Description |
|
|
889
|
+
| --- | --- |
|
|
890
|
+
| `viewExternalId` | View to aggregate. |
|
|
891
|
+
| `groupBy` | Groupable properties set to `true`; max 5 fields. |
|
|
892
|
+
| `filters` | Same filter syntax as `query()`. |
|
|
893
|
+
| `aggregate` | One of `avg`, `min`, `max`, `sum`, or `count`. |
|
|
910
894
|
|
|
911
|
-
|
|
895
|
+
Provide at least one of `groupBy` or `aggregate`. Omit `aggregate` to fetch distinct grouped values. The client requests up to 1000 aggregate rows.
|
|
912
896
|
|
|
913
|
-
|
|
|
914
|
-
|
|
915
|
-
| `
|
|
897
|
+
| Aggregate | Input | Use case |
|
|
898
|
+
| --- | --- | --- |
|
|
899
|
+
| `count` | `{ count: {} }` | Row count, optionally filtered. |
|
|
900
|
+
| `count` | `{ count: "name" }` | Count non-null values for a property. |
|
|
901
|
+
| `avg` | `{ avg: "volume" }` | Average of a numeric property. |
|
|
902
|
+
| `min` | `{ min: "volume" }` | Minimum numeric value. |
|
|
903
|
+
| `max` | `{ max: "volume" }` | Maximum numeric value. |
|
|
904
|
+
| `sum` | `{ sum: "volume" }` | Sum of a numeric property. |
|
|
905
|
+
|
|
906
|
+
### Filter Operators
|
|
907
|
+
|
|
908
|
+
| Field type | Operators |
|
|
909
|
+
| --- | --- |
|
|
910
|
+
| `string` | `eq`, `in`, `prefix`, `search`, `exists` |
|
|
916
911
|
| `number` | `eq`, `in`, `gt`, `gte`, `lt`, `lte`, `exists` |
|
|
917
912
|
| `boolean` | `eq`, `exists` |
|
|
918
|
-
| timestamp / `Date` | `eq`, `in`, `gt`, `gte`, `lt`, `lte`, `exists`
|
|
913
|
+
| timestamp / `Date` | `eq`, `in`, `gt`, `gte`, `lt`, `lte`, `exists` |
|
|
919
914
|
| `NodeId` | `eq`, `in`, `exists` |
|
|
915
|
+
| `string[]` | `containsAny`, `containsAll`, `search`, `exists` |
|
|
920
916
|
| `T[]` | `containsAny`, `containsAll`, `exists` |
|
|
921
917
|
|
|
922
|
-
Logical combinators `AND`, `OR`, and `NOT` are supported at any nesting level, including
|
|
918
|
+
Logical combinators `AND`, `OR`, and `NOT` are supported at any nesting level, including nested relation filters.
|
|
919
|
+
|
|
920
|
+
### Relation Traversal
|
|
921
|
+
|
|
922
|
+
| Relation type | Description |
|
|
923
|
+
| --- | --- |
|
|
924
|
+
| Direct relations | Outward node references such as `parent`, `asset`, and `unit`. |
|
|
925
|
+
| Reverse relations | Relations declared only in `TRelations`, such as `children` on `CogniteAsset`. |
|
|
926
|
+
| Edge relations | Edge-backed relations declared in `TRelations`, such as `images360` on `Cognite3DObject`. |
|
|
927
|
+
| Depth | Nested `select` and `filters` are supported up to 3 levels deep. |
|
|
928
|
+
|
|
929
|
+
### Exports
|
|
930
|
+
|
|
931
|
+
**Core**
|
|
923
932
|
|
|
924
|
-
|
|
933
|
+
| Symbol | Description |
|
|
934
|
+
| --- | --- |
|
|
935
|
+
| `IndustrialModelClient` | Main client for any FDM data model. |
|
|
936
|
+
| `IndustrialModel`, `ModelProps`, `ModelRelations` | Type helpers for model properties and relation metadata. |
|
|
937
|
+
| `NodeId`, `DataModelId` | Instance and data model identifiers. |
|
|
938
|
+
| `QuerySelect` | Type helper for reusable query selections. |
|
|
939
|
+
| `QueryResult`, `QueryResultItem` | Query output types. |
|
|
940
|
+
| `AggregateResult`, `AggregateResultItem` | Aggregate output types. |
|
|
941
|
+
| `IndustrialModelClientOptions` | Client configuration options. |
|
|
925
942
|
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
943
|
+
**Cognite Core**
|
|
944
|
+
|
|
945
|
+
| Symbol | Description |
|
|
946
|
+
| --- | --- |
|
|
947
|
+
| `CogniteCoreClient` | Convenience client pre-configured for `cdf_cdm/CogniteCore/v1`. |
|
|
948
|
+
| `COGNITE_CORE_DATA_MODEL` | Data model identifier constant for Cognite Core v1. |
|
|
949
|
+
| `CogniteCoreViewExternalId` | Union type of all Cognite Core view names. |
|
|
950
|
+
| `CogniteAsset`, `CogniteAssetClass`, `CogniteAssetType` | Asset hierarchy views. |
|
|
951
|
+
| `CogniteEquipment`, `CogniteEquipmentType` | Equipment views. |
|
|
952
|
+
| `CogniteFile`, `CogniteFileCategory` | File views. |
|
|
953
|
+
| `CogniteActivity` | Activity view. |
|
|
954
|
+
| `CogniteTimeSeries` | Time series view. |
|
|
955
|
+
| `CogniteUnit` | Unit of measurement view. |
|
|
956
|
+
| `CogniteAnnotation`, `CogniteDiagramAnnotation` | Annotation views. |
|
|
957
|
+
| `CogniteSourceSystem` | Source system view. |
|
|
958
|
+
| `CogniteDescribable`, `CogniteSourceable`, `CogniteSchedulable`, `CogniteVisualizable` | Mixin views. |
|
|
959
|
+
| `Cognite3DObject`, `Cognite3DModel`, `Cognite3DRevision`, `Cognite3DTransformation` | 3D object and model views. |
|
|
960
|
+
| `CogniteCADModel`, `CogniteCADRevision`, `CogniteCADNode` | CAD-specific views. |
|
|
961
|
+
| `CognitePointCloudModel`, `CognitePointCloudRevision`, `CognitePointCloudVolume` | Point cloud views. |
|
|
962
|
+
| `Cognite360Image`, `Cognite360ImageModel`, `Cognite360ImageCollection`, `Cognite360ImageStation`, `Cognite360ImageAnnotation` | 360 image views. |
|
|
963
|
+
| `CogniteCubeMap` | Cube map view. |
|
|
930
964
|
|
|
931
965
|
## Releasing
|
|
932
966
|
|