← Files WixARCHIVED FILE
skills/wix-app/references/data-collection/WIX_DATA.md
9.78 KB · Oct 8, 2026 · 12:02 UTC
# Wix Data SDK Reference
## Installation
`@wix/data` must be a dependency before use: `npm install @wix/data`.
`Cannot find module '@wix/data'` means it is not installed. Install it — never mock it.
## SDK Methods & Interfaces
All of these come from `import { items } from '@wix/data'`.
| Method Call | TypeScript Signature | Description |
| --- | --- | --- |
| `items.get()` | `(collectionId: string, itemId: string, options?: WixDataGetOptions) => Promise<WixDataItem \| null>` | Get a single item by ID |
| `items.query()` | `(collectionId: string) => WixDataQuery` | Build a chainable query (call `.find()` to execute) |
| `items.insert()` | `(collectionId: string, item: Partial<WixDataItem>, options?: WixDataInsertOptions) => Promise<WixDataItem>` | Add a new item to a collection |
| `items.update()` | `(collectionId: string, item: WixDataItem, options?: WixDataUpdateOptions) => Promise<WixDataItem>` | Replace an existing item (item MUST include `_id`) |
| `items.save()` | `(collectionId: string, item: Partial<WixDataItem>, options?: WixDataSaveOptions) => Promise<WixDataItem>` | Insert or update (upsert) based on `_id` |
| `items.remove()` | `(collectionId: string, itemId: string, options?: WixDataRemoveOptions) => Promise<WixDataItem \| null>` | Remove an item by ID |
| `items.bulkInsert()` | `(collectionId: string, items: Partial<WixDataItem>[], options?: WixDataOptions) => Promise<WixDataBulkResult>` | Insert multiple items (max 1000) |
| `items.bulkUpdate()` | `(collectionId: string, items: WixDataItem[], options?: WixDataBulkUpdateOptions) => Promise<WixDataBulkResult>` | Update multiple items (max 1000) |
| `items.bulkRemove()` | `(collectionId: string, itemIds: string[], options?: WixDataBulkRemoveOptions) => Promise<WixDataBulkResult>` | Remove multiple items (max 1000) |
| `items.filter()` | `() => WixDataFilter` | Create a standalone filter (for use with `.or()`, `.and()`, `.not()`) |
## ⚠️ Common Wrong Method Names (DO NOT USE)
| ❌ WRONG (does not exist) | ✅ CORRECT |
| --- | --- |
| `items.queryDataItems()` | `items.query("Collection").find()` |
| `items.insertDataItem()` | `items.insert("Collection", data)` |
| `items.updateDataItem()` | `items.update("Collection", data)` |
| `items.removeDataItem()` | `items.remove("Collection", id)` |
| `items.getDataItem()` | `items.get("Collection", itemId)` |
| `items.bulkInsertDataItems()` | `items.bulkInsert("Collection", items)` |
If you see any method with `DataItem` in the name, it is **wrong**.
## Full Type Definitions
### WixDataItem
```ts
interface WixDataItem {
_id: string;
_createdDate?: Date; // read-only, set by Wix on insert
_updatedDate?: Date; // read-only, set by Wix on insert/update
_owner?: string; // ID of the user who created the item
[key: string]: any; // custom fields from your collection schema
}
```
### WixDataResult (returned by `query().find()`)
```ts
interface WixDataResult {
readonly items: WixDataItem[];
readonly totalCount: number | undefined; // both only when returnTotalCount: true
readonly totalPages: number | undefined;
readonly pageSize: number | undefined;
readonly currentPage: number | undefined;
readonly length: number;
hasNext(): boolean;
hasPrev(): boolean;
next(): Promise<WixDataResult>;
prev(): Promise<WixDataResult>;
}
```
### WixDataQuery (returned by `items.query()`)
Chainable. Build filters, then `.find()`, `.count()` or `.distinct()`.
```ts
interface WixDataQuery {
// --- Filters ---
eq(field: string, value: any): WixDataQuery;
ne(field: string, value: any): WixDataQuery;
gt(field: string, value: string | number | Date): WixDataQuery;
ge(field: string, value: string | number | Date): WixDataQuery;
lt(field: string, value: string | number | Date): WixDataQuery;
le(field: string, value: string | number | Date): WixDataQuery;
between(field: string, rangeStart: string | number | Date, rangeEnd: string | number | Date): WixDataQuery;
contains(field: string, value: string): WixDataQuery;
startsWith(field: string, value: string): WixDataQuery;
endsWith(field: string, value: string): WixDataQuery;
hasSome(field: string, values: string[] | number[] | Date[]): WixDataQuery;
hasAll(field: string, values: string[] | number[] | Date[]): WixDataQuery;
isEmpty(field: string): WixDataQuery;
isNotEmpty(field: string): WixDataQuery;
// --- Logical operators ---
or(filter: WixDataFilter): WixDataQuery;
and(filter: WixDataFilter): WixDataQuery;
not(filter: WixDataFilter): WixDataQuery;
// --- Sorting ---
ascending(...fields: string[]): WixDataQuery;
descending(...fields: string[]): WixDataQuery;
// --- Pagination ---
limit(limitNumber: number): WixDataQuery; // default 50, max 1000
skip(skipCount: number): WixDataQuery;
// --- Projection ---
fields(...fields: string[]): WixDataQuery;
include(...fields: string[]): WixDataQuery; // include referenced items
// --- Execute ---
find(options?: WixDataQueryOptions): Promise<WixDataResult>;
count(options?: WixDataReadOptions): Promise<number>;
distinct(field: string, options?: WixDataQueryOptions): Promise<WixDataResult<any>>;
}
```
### Options Types
```ts
interface WixDataOptions {
suppressHooks?: boolean; // skip beforeX/afterX hooks
showDrafts?: boolean; // include draft items
appOptions?: Record<string, any>;
}
interface WixDataReadOptions extends WixDataOptions {
language?: string; // IETF BCP 47 language tag
consistentRead?: boolean; // read from primary DB (slower but up-to-date)
}
interface WixDataQueryOptions extends WixDataReadOptions {
returnTotalCount?: boolean; // populate totalCount/totalPages in results
}
interface WixDataGetOptions extends WixDataReadOptions {
fields?: string[]; // fields to return
includeReferences?: { field: string; limit?: number }[];
includeFieldGroups?: string[];
}
// Insert/Save options add nothing to WixDataOptions.
// Update/Remove/BulkUpdate/BulkRemove options add an optional guard:
// condition?: WixDataFilter — only apply when the condition is met
```
### WixDataBulkResult (returned by bulk operations)
```ts
interface WixDataBulkResult {
inserted: number;
updated: number;
removed: number;
skipped: number;
errors: WixDataBulkError[];
insertedItemIds: string[];
updatedItemIds: string[];
removedItemIds: string[];
}
// WixDataBulkError extends Error with `code`, `originalIndex` (position in the
// request array) and `item` (the failed item or its id).
```
## Usage Examples
```typescript
import { items } from "@wix/data";
// --- Get by ID ---
const item = await items.get("MyCollection", "item-id-123");
// Returns WixDataItem | null
// --- Query with filters ---
const result = await items.query("MyCollection")
.eq("status", "active")
.gt("price", 10)
.ascending("name")
.limit(20)
.find();
// result.items: WixDataItem[]
// --- Compound query with or/and ---
// `or()` COMBINES two filters; it is not a condition. Called on a query or
// filter that holds no condition yet, it contributes an empty `{}` branch, and
// `{} OR x` matches the whole collection. Seed with the first condition, `or()`
// the rest onto it, then `and()` the result onto the query.
const pendingOrActive = items.filter().eq("status", "pending")
.or(items.filter().eq("status", "active"));
const result = await items.query("MyCollection").and(pendingOrActive).find();
// ❌ WRONG — or() onto a query holding no condition: matches every row
items.query("MyCollection").or(filter1).or(filter2);
// ❌ WRONG — or() onto the query itself: `country` is dropped from branch two
items.query("MyCollection").eq("country", "IL").contains("name", t).or(filter2);
// --- Insert ---
const created = await items.insert("MyCollection", {
title: "New Item",
price: 29.99,
});
// --- Update (MUST include _id) ---
await items.update("MyCollection", {
_id: "item-id-123",
title: "Updated Title",
price: 39.99,
});
// ❌ WRONG — three args
await items.update("MyCollection", "item-id", { title: "x" });
// ✅ CORRECT — _id inside data object
await items.update("MyCollection", { _id: "item-id", title: "x" });
// --- Remove ---
await items.remove("MyCollection", "item-id-123");
// --- Bulk Insert ---
const bulkResult = await items.bulkInsert("MyCollection", [
{ title: "Item 1" },
{ title: "Item 2" },
]);
// bulkResult.inserted: 2, bulkResult.insertedItemIds: [...]
```
## Collection Schema Rules
Use the collection id, field keys and field types exactly as the schema defines them. Custom fields
live in the `[key: string]: any` part of `WixDataItem`.
## Permissions
| Operation | Required Scope |
| --- | --- |
| `get`, `query`, `count`, `distinct` | `SCOPE.DC-DATA.READ` |
| `insert`, `update`, `save`, `remove`, `bulkInsert`, `bulkUpdate`, `bulkRemove` | `SCOPE.DC-DATA.WRITE` |
### Elevating permissions (backend only)
In backend code (service plugins, events, backend APIs), wrap the `items` method with `auth.elevate` from `@wix/essentials` to run with elevated permissions:
```typescript
import { auth } from '@wix/essentials';
const elevatedQuery = auth.elevate(items.query);
const configResult = await elevatedQuery('MyCollection').find();
```
## Date/Time Handling
- **Date (date-only)**: Store as a string in "YYYY-MM-DD" format (as returned by `<input type="date" />`).
- **DateTime (date + time)**: Store as a Date object. Accept the YYYY-MM-DDTHH:mm format returned by `<input type="datetime-local" />` and convert to a Date object using `new Date()`.
- **Time (time-only)**: Store as a string in HH:mm or HH:mm:ss 24-hour format (as returned by `<input type="time" />`).
- Use native JavaScript Date methods for parsing, formatting, and manipulating dates/times (e.g., `new Date()`, `toISOString()`, `toLocaleString()`, `toLocaleDateString()`).
- Always validate incoming date/time values and provide graceful fallback or explicit error handling when values are invalid.
SHA-256: 826cf81a28f33b167cafb8a0f4cabcb4ea9e3f73bdd0690a5ce624053a07df0d