industrial-model 0.3.0 → 0.5.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 +217 -2
- package/dist/index.cjs +458 -137
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +81 -2
- package/dist/index.d.ts +81 -2
- package/dist/index.js +458 -137
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,6 +6,7 @@ TypeScript SDK for querying [Cognite Flexible Data Models (FDM)](https://docs.co
|
|
|
6
6
|
|
|
7
7
|
- **Type-safe queries** — define your data model types once, get compile-time validation on filters, selects, and sorts
|
|
8
8
|
- **Relation traversal** — query nested relations (edges/nodes) up to 3 levels deep with automatic pagination
|
|
9
|
+
- **Text search filters** — use Cognite `instances.search` from query and aggregate filters on text fields
|
|
9
10
|
- **Dual CJS/ESM** — works in Node.js and bundlers out of the box
|
|
10
11
|
- **Cursor-based pagination** — built-in support for iterating large result sets
|
|
11
12
|
|
|
@@ -60,9 +61,10 @@ const { items } = await model.query<{ name: string; description: string }>()({
|
|
|
60
61
|
| Setup & types | [Shared type definitions](#shared-type-definitions) |
|
|
61
62
|
| Basic queries | [Query assets](#query-assets), [Single asset](#query-a-single-asset-by-externalid) |
|
|
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) |
|
|
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
|
+
| 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) |
|
|
64
65
|
| Select & sort | [Select all scalars](#select-all-scalar-fields), [Multi-field sort](#sort-by-multiple-fields) |
|
|
65
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) |
|
|
66
68
|
| Advanced | [Custom data model](#use-a-custom-data-model), [Full query](#full-example-assets-equipment-and-filters) |
|
|
67
69
|
|
|
68
70
|
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`.
|
|
@@ -468,6 +470,52 @@ const fullyTagged = await model.query<CogniteAsset>()({
|
|
|
468
470
|
|
|
469
471
|
---
|
|
470
472
|
|
|
473
|
+
### Search text fields
|
|
474
|
+
|
|
475
|
+
Use `search` on text properties and string-list text properties when you want Cognite full-text matching instead of exact or prefix filters. The optional `operator` is passed to Cognite search and defaults to `"OR"`; use `"AND"` when every term should match.
|
|
476
|
+
|
|
477
|
+
```ts
|
|
478
|
+
const { items } = await model.query<CogniteAsset>()({
|
|
479
|
+
viewExternalId: "CogniteAsset",
|
|
480
|
+
select: { name: true, description: true, tags: true },
|
|
481
|
+
filters: {
|
|
482
|
+
name: { search: { query: "root pump", operator: "AND" } },
|
|
483
|
+
tags: { search: { query: "critical" } },
|
|
484
|
+
},
|
|
485
|
+
limit: 100,
|
|
486
|
+
});
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
Search filters can be combined with normal field operators. The SDK first calls Cognite `instances.search`, then adds the returned node references to the regular query filter.
|
|
490
|
+
|
|
491
|
+
```ts
|
|
492
|
+
const pumps = await model.query<CogniteAsset>()({
|
|
493
|
+
viewExternalId: "CogniteAsset",
|
|
494
|
+
select: { name: true, sourceId: true },
|
|
495
|
+
filters: {
|
|
496
|
+
name: {
|
|
497
|
+
prefix: "Pump",
|
|
498
|
+
search: { query: "motor" },
|
|
499
|
+
},
|
|
500
|
+
sourceId: { exists: true },
|
|
501
|
+
},
|
|
502
|
+
});
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
The same filter syntax is also supported by `aggregate`:
|
|
506
|
+
|
|
507
|
+
```ts
|
|
508
|
+
const { items } = await model.aggregate<CogniteAsset>()({
|
|
509
|
+
viewExternalId: "CogniteAsset",
|
|
510
|
+
aggregate: { count: {} },
|
|
511
|
+
filters: {
|
|
512
|
+
name: { search: { query: "compressor seal" } },
|
|
513
|
+
},
|
|
514
|
+
});
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
---
|
|
518
|
+
|
|
471
519
|
### Filter on related nodes
|
|
472
520
|
|
|
473
521
|
Filter the root view based on properties of a direct or nested relation. This uses Cognite nested filters under the hood.
|
|
@@ -661,6 +709,135 @@ if (cursor) {
|
|
|
661
709
|
|
|
662
710
|
---
|
|
663
711
|
|
|
712
|
+
### Count assets by source ID
|
|
713
|
+
|
|
714
|
+
Group assets and count how many share each `sourceId`. Uses the same `filters` syntax as `query`.
|
|
715
|
+
|
|
716
|
+
```ts
|
|
717
|
+
const { items } = await model.aggregate<CogniteAsset>()({
|
|
718
|
+
viewExternalId: "CogniteAsset",
|
|
719
|
+
groupBy: { sourceId: true },
|
|
720
|
+
aggregate: { count: {} },
|
|
721
|
+
filters: { name: { prefix: "WMT" } },
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
for (const row of items) {
|
|
725
|
+
console.log(row.group?.sourceId, row.aggregate?.value);
|
|
726
|
+
}
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
---
|
|
730
|
+
|
|
731
|
+
### List distinct source IDs
|
|
732
|
+
|
|
733
|
+
Omit `aggregate` to return unique combinations of the `groupBy` fields (up to 1000 groups).
|
|
734
|
+
|
|
735
|
+
```ts
|
|
736
|
+
const { items } = await model.aggregate<CogniteAsset>()({
|
|
737
|
+
viewExternalId: "CogniteAsset",
|
|
738
|
+
groupBy: { sourceId: true },
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
const sourceIds = items.map((row) => row.group?.sourceId);
|
|
742
|
+
```
|
|
743
|
+
|
|
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.
|
|
749
|
+
|
|
750
|
+
```ts
|
|
751
|
+
type PointCloudVolume = IndustrialModel<{
|
|
752
|
+
volume: number;
|
|
753
|
+
volumeType: string;
|
|
754
|
+
}>;
|
|
755
|
+
|
|
756
|
+
const { items } = await model.aggregate<PointCloudVolume>()({
|
|
757
|
+
viewExternalId: "CognitePointCloudVolume",
|
|
758
|
+
groupBy: { volumeType: true },
|
|
759
|
+
aggregate: { avg: "volume" },
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
items[0]?.group?.volumeType;
|
|
763
|
+
items[0]?.aggregate?.property; // "volume"
|
|
764
|
+
items[0]?.aggregate?.value;
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
Other numeric aggregates:
|
|
768
|
+
|
|
769
|
+
```ts
|
|
770
|
+
await model.aggregate<PointCloudVolume>()({
|
|
771
|
+
viewExternalId: "CognitePointCloudVolume",
|
|
772
|
+
aggregate: { min: "volume" },
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
await model.aggregate<PointCloudVolume>()({
|
|
776
|
+
viewExternalId: "CognitePointCloudVolume",
|
|
777
|
+
aggregate: { max: "volume" },
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
await model.aggregate<PointCloudVolume>()({
|
|
781
|
+
viewExternalId: "CognitePointCloudVolume",
|
|
782
|
+
aggregate: { sum: "volume" },
|
|
783
|
+
});
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
---
|
|
787
|
+
|
|
788
|
+
### Count non-null values for a property
|
|
789
|
+
|
|
790
|
+
```ts
|
|
791
|
+
const { items } = await model.aggregate<CogniteAsset>()({
|
|
792
|
+
viewExternalId: "CogniteAsset",
|
|
793
|
+
aggregate: { count: "name" },
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
items[0]?.aggregate?.property; // "name"
|
|
797
|
+
items[0]?.aggregate?.value;
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
---
|
|
801
|
+
|
|
802
|
+
### Count all matching assets
|
|
803
|
+
|
|
804
|
+
A global count with no `groupBy`:
|
|
805
|
+
|
|
806
|
+
```ts
|
|
807
|
+
const { items } = await model.aggregate<CogniteAsset>()({
|
|
808
|
+
viewExternalId: "CogniteAsset",
|
|
809
|
+
aggregate: { count: {} },
|
|
810
|
+
filters: {
|
|
811
|
+
OR: [{ tags: { containsAny: ["critical"] } }, { sourceId: { eq: "sap" } }],
|
|
812
|
+
},
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
items[0]?.aggregate?.value;
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
---
|
|
819
|
+
|
|
820
|
+
### Group by a direct relation
|
|
821
|
+
|
|
822
|
+
`groupBy` supports direct relations; results are returned as `NodeId` objects.
|
|
823
|
+
|
|
824
|
+
```ts
|
|
825
|
+
type PointCloudVolume = IndustrialModel<{
|
|
826
|
+
volume: number;
|
|
827
|
+
object3D?: NodeId;
|
|
828
|
+
}>;
|
|
829
|
+
|
|
830
|
+
const { items } = await model.aggregate<PointCloudVolume>()({
|
|
831
|
+
viewExternalId: "CognitePointCloudVolume",
|
|
832
|
+
groupBy: { object3D: true },
|
|
833
|
+
aggregate: { sum: "volume" },
|
|
834
|
+
});
|
|
835
|
+
|
|
836
|
+
items[0]?.group?.object3D?.externalId;
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
---
|
|
840
|
+
|
|
664
841
|
## API
|
|
665
842
|
|
|
666
843
|
### Exports
|
|
@@ -672,6 +849,8 @@ if (cursor) {
|
|
|
672
849
|
| `NodeId`, `DataModelId` | Instance and data-model identifiers |
|
|
673
850
|
| `QueryOptions`, `QuerySelect`, `WhereInput`, `SortInput` | Query input types |
|
|
674
851
|
| `QueryResult`, `QueryResultItem`, `QueryResultMetadata` | Query output types |
|
|
852
|
+
| `AggregateOptions`, `AggregateGroupBy`, `AggregateDefinition` | Aggregate input types |
|
|
853
|
+
| `AggregateResult`, `AggregateResultItem`, `GroupByKey` | Aggregate output types |
|
|
675
854
|
| `buildViewSchema`, `nodeIdSchema` | Zod schemas built from Cognite view metadata |
|
|
676
855
|
| `SortDirection` | `"ascending"` \| `"descending"` |
|
|
677
856
|
|
|
@@ -737,6 +916,39 @@ items[0]?.parent?.name;
|
|
|
737
916
|
items[0]?.externalId;
|
|
738
917
|
```
|
|
739
918
|
|
|
919
|
+
### `model.aggregate<TModel>()(options)`
|
|
920
|
+
|
|
921
|
+
| Option | Type | Description |
|
|
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 |
|
|
927
|
+
|
|
928
|
+
Provide at least one of `groupBy` or `aggregate`. Omit `aggregate` to fetch distinct values for the grouped fields. The client always requests nodes with `limit: 1000`.
|
|
929
|
+
|
|
930
|
+
`aggregate()` uses the same curried form as `query`. Each result item has the shape:
|
|
931
|
+
|
|
932
|
+
```ts
|
|
933
|
+
type AggregateResultItem = {
|
|
934
|
+
group?: { /* keys from groupBy */ };
|
|
935
|
+
aggregate?: { property?: string; value: number };
|
|
936
|
+
};
|
|
937
|
+
```
|
|
938
|
+
|
|
939
|
+
When counting all rows, `aggregate` has only `value` (no `property`). When aggregating a field, `property` matches the name you passed in the request.
|
|
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.
|
|
951
|
+
|
|
740
952
|
### Automatic query behavior
|
|
741
953
|
|
|
742
954
|
- **`hasData` filter** — every root query includes a `hasData` constraint for the target view.
|
|
@@ -747,15 +959,18 @@ items[0]?.externalId;
|
|
|
747
959
|
|
|
748
960
|
| Type | Operators |
|
|
749
961
|
|------|-----------|
|
|
750
|
-
| `string` | `eq`, `in`, `prefix`, `exists` |
|
|
962
|
+
| `string` | `eq`, `in`, `prefix`, `search`, `exists` |
|
|
751
963
|
| `number` | `eq`, `in`, `gt`, `gte`, `lt`, `lte`, `exists` |
|
|
752
964
|
| `boolean` | `eq`, `exists` |
|
|
753
965
|
| timestamp / `Date` | `eq`, `in`, `gt`, `gte`, `lt`, `lte`, `exists` — use ISO strings or `Date` values (coerced to ISO) |
|
|
754
966
|
| `NodeId` | `eq`, `in`, `exists` |
|
|
967
|
+
| `string[]` | `containsAny`, `containsAll`, `search`, `exists` |
|
|
755
968
|
| `T[]` | `containsAny`, `containsAll`, `exists` |
|
|
756
969
|
|
|
757
970
|
Logical combinators `AND`, `OR`, and `NOT` are supported at any nesting level, including inside nested relation filters (e.g. `parent: { OR: [...] }`).
|
|
758
971
|
|
|
972
|
+
`search` is available for Cognite text properties and string-list text properties. It is not accepted on node metadata fields such as `externalId` or `space`. Each `search` filter uses `instances.search` with `limit: 1000`, maps the matched nodes to `instanceReferences`, and applies those references to the query or aggregate request.
|
|
973
|
+
|
|
759
974
|
### Relation traversal
|
|
760
975
|
|
|
761
976
|
- **Direct relations** — `parent`, `asset`, `unit` (outwards from the current node). List relations such as `path` return arrays when expanded.
|