Table of Contents
Collections
Collections are the primary way to structure and organize your data in VSKI. Each collection has a schema that defines the fields and their types.
Collections can live in in different databases, but collection metadata is
stored in the default database.
Creating Collections
Basic Collection
const collection = await client.settings.collections.create({
name: "posts",
type: "base",
fields: [
{ name: "title", type: "text", required: true },
{ name: "content", type: "text" },
{ name: "published", type: "bool" },
{ name: "views", type: "number" },
],
});
Field Types
| Type | Description | Example |
|---|---|---|
text |
Plain text string | "Hello" |
email |
Email address | "user@example.com" |
number |
Numeric value | 42 or 3.14 |
bool |
Boolean value | true or false |
date |
Date string | "2024-01-01" |
datetime |
Datetime with timezone | "2024-01-01T00:00:00Z" |
select |
Predefined options | Use with options array |
url |
URL string | "https://example.com" |
editor |
Rich text content | HTML/Markdown content |
json |
JSON object | { "key": "value" } |
relation |
Reference to another collection | Use with collectionId |
Auth Collections
const usersCollection = await client.settings.collections.create({
name: "_users",
type: "auth",
fields: [
{ name: "email", type: "email", required: true },
{ name: "password", type: "text", required: true },
{ name: "name", type: "text" },
],
});
Auth collections automatically include system fields (id, created,
updated).
Note: When creating collections, use the fields property. However, when
reading collection data, the schema is returned as the schema property. Both
keys are accepted for backwards compatibility.
Creating Records
Simple Create
const post = await client.collection("posts").create({
title: "Hello World",
content: "My first post",
published: true,
views: 0,
});
console.log(post.id); // Auto-generated ID
console.log(post.created); // Auto timestamp
console.log(post.updated); // Auto timestamp
Using Custom ID
const post = await client.collection("posts").create({
id: "custom-post-id",
title: "Custom ID Post",
content: "Content here",
});
Reading Records
Get Single Record
const post = await client.collection("posts").getOne("record-id");
console.log(post.title);
List Records
const list = await client.collection("posts").getList(1, 20);
console.log(list.totalItems); // Total number of records
console.log(list.items); // Array of records on this page
console.log(list.totalPages); // Total pages
Filter Records
const filtered = await client.collection("posts").getList(1, 20, {
filter: "published = true AND views > 10",
});
Sort Records
const sorted = await client.collection("posts").getList(1, 20, {
sort: "-created", // Descending by creation date
});
// Multiple sort fields
const sorted2 = await client.collection("posts").getList(1, 20, {
sort: "-published,created",
});
Select Specific Fields
const partial = await client.collection("posts").getList(1, 20, {
fields: "id,title,published",
});
Updating Records
Update All Fields
const updated = await client.collection("posts").update("record-id", {
title: "Updated Title",
views: 100,
});
Partial Update (preserve unchanged fields)
const updated = await client.collection("posts").update("record-id", {
title: "Just the title",
});
Deleting Records
const success = await client.collection("posts").delete("record-id");
console.log(success); // true
Query Filters
VSKI supports powerful SQL-like filters:
Comparison Operators
// Equals
client.filter("title = 'Hello'");
// Not equals
client.filter("status != 'deleted'");
// Greater than
client.filter("views > 100");
// Less than
client.filter("price < 50");
// Greater than or equal
client.filter("rating >= 4");
// Less than or equal
client.filter("age <= 18");
Logical Operators
// AND
client.filter("published = true AND featured = true");
// OR
client.filter("status = 'active' OR status = 'pending'");
// Parentheses for grouping
client.filter("(status = 'active' OR status = 'pending') AND published = true");
String Operators
// Contains (LIKE with wildcards)
client.filter("title ~ 'Hello'");
// Case-insensitive LIKE
client.filter("title LIKE 'hello'");
// Exact match with quotes
client.filter("title = 'Hello World'");
Note: The
~operator performs a substring match (LIKE with wildcards). For prefix or suffix matching, use explicit wildcards:title ~ 'Hello%'is not needed as%wildcards are added automatically.
Null Checks
// Is null
client.filter("deleted = null");
// Is not null
client.filter("deleted != null");
Array Operations (for JSON fields)
// In array
client.filter("tags ~ ['javascript', 'typescript']");
// Contains array element
client.filter("tags ~ 'javascript'");
Pagination
// Get first page
const page1 = await client.collection("posts").getList(1, 20);
// Get next page
const page2 = await client.collection("posts").getList(2, 20);
// Check if there are more pages
if (page1.page < page1.totalPages) {
// There are more pages
}
Expand Relations
When you have relation fields, you can expand them:
const post = await client.collection("posts").getOne("post-id", {
expand: "author,category",
});
console.log(post.expand.author); // Full author record
console.log(post.expand.category); // Full category record
Collection Management
List Collections
const collections = await client.settings.collections.getList();
console.log(collections.items);
Get Collection Details
// Note: getOne method is not currently available
// Use getList to retrieve all collections and find by name
const collections = await client.settings.collections.getList();
const collection = collections.items.find((c) => c.name === "collection-name");
console.log(collection.name);
console.log(collection.schema);
Update Collection Schema
const updated = await client.settings.collections.update("collection-id", {
fields: [
{ name: "title", type: "text", required: true },
{ name: "content", type: "text" },
{ name: "newField", type: "text" }, // Added new field
],
});
Delete Collection
await client.settings.collections.delete("collection-id");
Warning: This will delete all records in the collection.
Best Practices
- Use meaningful field names - Follow consistent naming conventions
- Set required fields - Use
required: truefor essential data - Index frequently queried fields - Improve query performance
- Use appropriate types - Choose the most specific type for your data
- Validate on client side - Reduce unnecessary API calls
- Use pagination - Always use
getList()with limits for large datasets
API Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/collections |
List collections |
POST |
/api/collections |
Create collection |
GET |
/api/collections/:name |
Get collection |
PATCH |
/api/collections/:name |
Update collection |
DELETE |
/api/collections/:name |
Delete collection |
GET |
/api/collections/:name/records |
List records |
POST |
/api/collections/:name/records |
Create record |
GET |
/api/collections/:name/records/:recordId |
Get record |
PATCH |
/api/collections/:name/records/:recordId |
Update record |
PUT |
/api/collections/:name/records/:recordId |
Update record (full) |
DELETE |
/api/collections/:name/records/:recordId |
Delete record |
PATCH |
/api/collections/:name/records/bulk |
Bulk update records |
DELETE |
/api/collections/:name/records/bulk |
Bulk delete records |
GET |
/api/collections/:name/records/search |
Full-text search records |
GET |
/api/collections/:name/records/views/:slug |
Get records from view |