Using Interfaces
We recommend using Classes and Decorators to define the data model. However, if you prefer to not use class decorators you can define the collection schema using Interfaces. This section describes how to define the data model using Interfaces.
Declaring Models
Below we describe how the database models can be defined.
// data container
interface Catalog extends TigrisCollectionType {
id?: string;
name: string;
price: number;
brand: string;
labels: string;
popularity: number;
entryDate: Date;
available: boolean;
}
// schema definition
const catalogSchema: TigrisSchema<Catalog> = {
id: {
type: TigrisDataTypes.STRING,
primary_key: {
order: 1,
autoGenerate: true,
},
},
name: {
type: TigrisDataTypes.STRING,
},
price: {
type: TigrisDataTypes.NUMBER,
},
brand: {
type: TigrisDataTypes.STRING,
},
labels: {
type: TigrisDataTypes.STRING,
},
popularity: {
type: TigrisDataTypes.INT32,
},
entryDate: {
type: TigrisDataTypes.DATE_TIME,
timestamp: "createdAt"
},
available: {
type: TigrisDataTypes.BOOLEAN,
default: false
},
};
Essentially, schema is modeled as two parts:
- Data containers - interface that holds the data model
- Schema of Data containers - TigrisSchema definition of these data containers.
// data container
interface Catalog extends TigrisCollectionType {
id?: string;
name: string;
}
// schema definition
const catalogSchema: TigrisSchema<Catalog> = {
id: {
type: TigrisDataTypes.INT64,
primary_key: {
order: 1,
autoGenerate: true,
},
},
name: { type: TigrisDataTypes.STRING },
};
You must keep the data container and schema definition in sync.
Embedded Data Model
Tigris offers rich documents that enable embedding related data in a single document. Embedded models allow applications to complete database operations with fewer queries or updates, thus reducing query activity and increasing efficiency.
Below is an example of embedded data model. We first define the ProductItem
type and then embed it inside the Order
type.
// data containers
export interface ProductItem {
productId: string;
quantity: number;
}
export interface Order extends TigrisCollectionType {
orderId?: string;
userId: bigint;
orderTotal: number;
productItems: ProductItem[];
}
// schema definitions
const productItemSchema: TigrisSchema<ProductItem> = {
productId: {
type: TigrisDataTypes.STRING,
},
quantity: {
type: TigrisDataTypes.NUMBER,
},
};
export const orderSchema: TigrisSchema<Order> = {
orderId: {
type: TigrisDataTypes.INT64,
primary_key: {
order: 1,
autoGenerate: true,
},
},
userId: {
type: TigrisDataTypes.NUMBER_BIGINT,
},
orderTotal: {
type: TigrisDataTypes.NUMBER,
},
productItems: {
type: TigrisDataTypes.ARRAY,
items: {
type: productItemSchema,
},
},
};
Arrays in documents
Including arrays in your schema requires items
attribute to identify its
contents.
export interface City extends TigrisCollectionType {
name: string;
neighborhoods: Array<string>;
}
export const CitySchema: TigrisSchema<City> = {
name: {
type: TigrisDataTypes.STRING,
primary_key: {
order: 1
}
},
neighborhoods: {
type: TigrisDataTypes.ARRAY,
items: {
type: TigrisDataTypes.STRING
},
},
};
Array of array(s)
Following example demonstrates a collection schema with nested arrays:
export interface Cell {
x: number;
y: number;
value: string;
}
export interface Matrix extends TigrisCollectionType {
id: string;
cells: Array<Array<Array<Cell>>>;
}
export const MatrixSchema: TigrisSchema<Matrix> = {
id: {
type: TigrisDataTypes.STRING,
primary_key: {
order: 1
}
},
cells: {
type: TigrisDataTypes.ARRAY,
items: {
type: TigrisDataTypes.ARRAY,
items: {
type: TigrisDataTypes.ARRAY,
items: {
type: {
x: {
type: TigrisDataTypes.NUMBER,
},
y: {
type: TigrisDataTypes.NUMBER,
},
value: {
type: TigrisDataTypes.STRING,
},
},
},
},
},
},
};
Create a Collection
Creates a collection with the model and any new operation will see the changes.
const catalog = await db.createOrUpdateCollection<Catalog>(
"catalog",
catalogSchema
);
Drop a Collection
Drops a collection with the model and any new operation will see the changes.
await db.dropCollection(Catalog);
List Collections
Lists all the collections in the database.
await db.listCollections();
Drop all Collections
Drops all collections in the database.
await db.dropAllCollections(Catalog);
Data Types
Tigris supports the majority of the primitive TypeScript types while also providing support for custom types.
- primitive types:
string
,boolean
,number
,bigint
,Date
,object
. - Custom types: user-defined class to define custom types.
- Array and object of all of above is supported.
Working with 64-bit integers (BigInt)
If your collection field has a use-case for 64-bit integers, we recommend using bigint
or string
field type to represent
your integers. If chose to use bigint
primitive type, please enable {supportBigInt: true}
flag
in the client configuration.
64-bit integers using String
// data container
export interface CatalogCategory {
name: string;
code: string;
}
// schema definition
export const categorySchema: TigrisSchema<CatalogCategory> = {
name: {
type: TigrisDataTypes.STRING,
},
code: {
type: TigrisDataTypes.NUMBER_BIGINT,
},
};
64-bit integers using BigInt
const tigris = new Tigris({
serverUrl: "api.preview.tigrisdata.cloud",
clientId: "paste client_id here",
clientSecret: "paste client_secret here",
projectName: "paste project name here",
supportBigInt: true
});
// data container
export interface CatalogCategory {
name: string;
code: bigint;
}
// schema definition
export const categorySchema: TigrisSchema<CatalogCategory> = {
name: {
type: TigrisDataTypes.STRING,
},
code: {
type: TigrisDataTypes.NUMBER_BIGINT,
},
};
Primary Key
A primary key uniquely identifies a document in the collection and enforces the unique constraint. In the absence of a user-defined primary key, it is auto-generated.
Defining a Primary Key
The example above demonstrates how primary key is defined. The order
attribute
in primaryKey
represents the order of the field in the primary key. While
autoGenerate: true
represents that the values for this field will be
automatically generated by the Tigris server.
Composite Primary Key
Composite primary keys are also supported but in case of composite keys order of the fields is important. The example below demonstrates how the order of the fields are defined in case of a composite primary key.
// data container
interface Catalog extends TigrisCollectionType {
id?: number;
name: string;
}
// schema definition
const catalogSchema: TigrisSchema<Catalog> = {
id: {
type: TigrisDataTypes.INT32,
primary_key: {
order: 1,
autoGenerate: true,
},
},
name: {
type: TigrisDataTypes.STRING,
primary_key: {
order: 2,
},
},
};
Modifying Schema
Step 1: Update the data model in your application code
// data containers
export interface ProductAttributes {
name: string;
value: string;
}
export interface Catalog extends TigrisCollectionType {
id: bigint;
name: string;
price: number;
attributes: Array<ProductAttributes>;
+ brand: string
}
// schema definitions
const attributesSchema: TigrisSchema<ProductAttributes> {
name: {
type: TigrisDataTypes.STRING,
},
value: {
type: TigrisDataTypes.STRING,
}
}
const catalogSchema: TigrisSchema<Catalog> {
id: {
type: TigrisDataTypes.INT64,
primary_key: {
order: 1,
autoGenerate: true,
},
},
name: {
type: TigrisDataTypes.STRING,
},
price: {
type: TigrisDataTypes.NUMBER,
},
attributes: {
type: TigrisDataTypes.ARRAY,
items: {
attributesSchema
}
},
+ brand: {
+ type: TigrisDataTypes.STRING,
+ },
}
Step 2: Update the Collection
Updates the collection with the new model and any new operation will see the changes.
const catalog = await db.createOrUpdateCollection<Catalog>(
"catalog",
catalogSchema
);