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