Skip to content

Commit 8a8e04e

Browse files
committed
docs(databases): move custom timestamps to journey, remove bulk ops section, add next steps
1 parent cbfeeff commit 8a8e04e

File tree

3 files changed

+406
-469
lines changed

3 files changed

+406
-469
lines changed

src/routes/docs/products/databases/+layout.svelte

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@
8989
label: 'CSV imports',
9090
href: '/docs/products/databases/csv-imports',
9191
new: isNewUntil('31 Jul 2025')
92+
},
93+
{
94+
label: 'Custom timestamps',
95+
href: '/docs/products/databases/custom-timestamps'
9296
}
9397
]
9498
},
Lines changed: 384 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,384 @@
1+
---
2+
layout: article
3+
title: Custom timestamps
4+
description: Set custom $createdAt and $updatedAt timestamps for your documents when using server SDKs.
5+
---
6+
7+
When creating or updating documents, Appwrite automatically sets `$createdAt` and `$updatedAt` timestamps. However, there are scenarios where you might need to set these timestamps manually, such as when migrating data from another system or backfilling historical records.
8+
9+
{% info title="Server SDKs required" %}
10+
To manually set `$createdAt` and `$updatedAt`, you must use a **server SDK** with an **API key**. These attributes can be passed inside the `data` parameter on any of the create, update, or upsert routes (single or bulk).
11+
{% /info %}
12+
13+
# Setting custom timestamps {% #setting-custom-timestamps %}
14+
15+
You can override a document's timestamps by providing ISO 8601 strings (for example, `2025-08-10T12:34:56.000Z`) in the `data` payload. If these attributes are not provided, Appwrite will set them automatically.
16+
17+
## Single document operations {% #single-document-operations %}
18+
19+
### Create with custom timestamps {% #create-custom %}
20+
21+
{% multicode %}
22+
```server-nodejs
23+
const sdk = require('node-appwrite');
24+
25+
const client = new sdk.Client()
26+
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
27+
.setProject('<PROJECT_ID>')
28+
.setKey('<API_KEY>');
29+
30+
const databases = new sdk.Databases(client);
31+
32+
await databases.createDocument(
33+
'<DATABASE_ID>',
34+
'<COLLECTION_ID>',
35+
sdk.ID.unique(),
36+
{
37+
'$createdAt': new Date('2025-08-10T12:34:56.000Z').toISOString(),
38+
'$updatedAt': new Date('2025-08-10T12:34:56.000Z').toISOString(),
39+
// ...your attributes
40+
}
41+
);
42+
```
43+
```server-php
44+
use Appwrite\Client;
45+
use Appwrite\ID;
46+
use Appwrite\Services\Databases;
47+
48+
$client = (new Client())
49+
->setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
50+
->setProject('<YOUR_PROJECT_ID>')
51+
->setKey('<YOUR_API_KEY>');
52+
53+
$databases = new Databases($client);
54+
55+
$databases->createDocument(
56+
databaseId: '<DATABASE_ID>',
57+
collectionId: '<COLLECTION_ID>',
58+
documentId: '<DOCUMENT_ID>',
59+
[
60+
'$createdAt' => (new DateTime('<CUSTOM_DATE>'))->format(DATE_ATOM),
61+
'$updatedAt' => (new DateTime('<CUSTOM_DATE>'))->format(DATE_ATOM),
62+
// ...your attributes
63+
]
64+
);
65+
```
66+
```server-swift
67+
import Appwrite
68+
import Foundation
69+
70+
let client = Client()
71+
.setEndpoint("https://<REGION>.cloud.appwrite.io/v1")
72+
.setProject("<YOUR_PROJECT_ID>")
73+
.setKey("<YOUR_API_KEY>")
74+
75+
let databases = Databases(client)
76+
77+
let isoFormatter = ISO8601DateFormatter()
78+
isoFormatter.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
79+
let customDate = isoFormatter.date(from: "<CUSTOM_DATE>") ?? Date()
80+
let createdAt = isoFormatter.string(from: customDate)
81+
let updatedAt = isoFormatter.string(from: customDate)
82+
83+
do {
84+
let created = try await databases.createDocument(
85+
databaseId: "<DATABASE_ID>",
86+
collectionId: "<COLLECTION_ID>",
87+
documentId: "<DOCUMENT_ID>",
88+
data: [
89+
"$createdAt": createdAt,
90+
"$updatedAt": updatedAt,
91+
// ...your attributes
92+
]
93+
)
94+
print("Created:", created)
95+
} catch {
96+
print("Create error:", error)
97+
}
98+
```
99+
```server-python
100+
from appwrite.client import Client
101+
from appwrite.services.databases import Databases
102+
from appwrite.id import ID
103+
from datetime import datetime, timezone
104+
105+
client = Client()
106+
client.set_endpoint('https://<REGION>.cloud.appwrite.io/v1')
107+
client.set_project('<PROJECT_ID>')
108+
client.set_key('<API_KEY>')
109+
110+
databases = Databases(client)
111+
112+
iso = datetime(2025, 8, 10, 12, 34, 56, tzinfo=timezone.utc).isoformat()
113+
114+
databases.create_document(
115+
database_id='<DATABASE_ID>',
116+
collection_id='<COLLECTION_ID>',
117+
document_id=ID.unique(),
118+
data={
119+
'$createdAt': iso,
120+
'$updatedAt': iso,
121+
# ...your attributes
122+
}
123+
)
124+
```
125+
```server-ruby
126+
require 'appwrite'
127+
128+
include Appwrite
129+
130+
client = Client.new
131+
.set_endpoint('https://<REGION>.cloud.appwrite.io/v1')
132+
.set_project('<YOUR_PROJECT_ID>')
133+
.set_key('<YOUR_API_KEY>')
134+
135+
databases = Databases.new(client)
136+
137+
custom_date = Time.parse('2025-08-10T12:34:56.000Z').iso8601
138+
139+
databases.create_document(
140+
database_id: '<DATABASE_ID>',
141+
collection_id: '<COLLECTION_ID>',
142+
document_id: ID.unique(),
143+
data: {
144+
'$createdAt' => custom_date,
145+
'$updatedAt' => custom_date,
146+
# ...your attributes
147+
}
148+
)
149+
```
150+
```server-dotnet
151+
using Appwrite;
152+
using Appwrite.Models;
153+
using Appwrite.Services;
154+
155+
Client client = new Client()
156+
.SetEndPoint("https://<REGION>.cloud.appwrite.io/v1")
157+
.SetProject("<YOUR_PROJECT_ID>")
158+
.SetKey("<YOUR_API_KEY>");
159+
160+
Databases databases = new Databases(client);
161+
162+
string customDate = DateTimeOffset.Parse("2025-08-10T12:34:56.000Z").ToString("O");
163+
164+
await databases.CreateDocument(
165+
databaseId: "<DATABASE_ID>",
166+
collectionId: "<COLLECTION_ID>",
167+
documentId: ID.Unique(),
168+
data: new Dictionary<string, object>
169+
{
170+
["$createdAt"] = customDate,
171+
["$updatedAt"] = customDate,
172+
// ...your attributes
173+
}
174+
);
175+
```
176+
```server-dart
177+
import 'package:dart_appwrite/dart_appwrite.dart';
178+
179+
Client client = Client()
180+
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1')
181+
.setProject('<YOUR_PROJECT_ID>')
182+
.setKey('<YOUR_API_KEY>');
183+
184+
Databases databases = Databases(client);
185+
186+
String customDate = DateTime.parse('2025-08-10T12:34:56.000Z').toIso8601String();
187+
188+
await databases.createDocument(
189+
databaseId: '<DATABASE_ID>',
190+
collectionId: '<COLLECTION_ID>',
191+
documentId: ID.unique(),
192+
data: {
193+
'\$createdAt': customDate,
194+
'\$updatedAt': customDate,
195+
// ...your attributes
196+
},
197+
);
198+
```
199+
{% /multicode %}
200+
201+
### Update with custom timestamps {% #update-custom %}
202+
203+
When updating documents, you can also set a custom `$updatedAt` timestamp:
204+
205+
{% multicode %}
206+
```server-nodejs
207+
await databases.updateDocument(
208+
'<DATABASE_ID>',
209+
'<COLLECTION_ID>',
210+
'<DOCUMENT_ID>',
211+
{
212+
'$updatedAt': new Date('2025-08-10T12:34:56.000Z').toISOString(),
213+
// ...your attributes
214+
}
215+
);
216+
```
217+
```server-php
218+
$databases->updateDocument(
219+
databaseId: '<DATABASE_ID>',
220+
collectionId: '<COLLECTION_ID>',
221+
documentId: '<DOCUMENT_ID>',
222+
[
223+
'$updatedAt': (new DateTime('<CUSTOM_DATE>'))->format(DATE_ATOM),
224+
// ...your attributes
225+
]
226+
);
227+
```
228+
```server-python
229+
databases.update_document(
230+
database_id='<DATABASE_ID>',
231+
collection_id='<COLLECTION_ID>',
232+
document_id='<DOCUMENT_ID>',
233+
data={
234+
'$updatedAt': iso,
235+
# ...your attributes
236+
}
237+
)
238+
```
239+
{% /multicode %}
240+
241+
## Bulk operations {% #bulk-operations %}
242+
243+
Custom timestamps also work with bulk operations, allowing you to set different timestamps for each document in the batch:
244+
245+
### Bulk create {% #bulk-create %}
246+
247+
{% multicode %}
248+
```server-nodejs
249+
await databases.createDocuments(
250+
'<DATABASE_ID>',
251+
'<COLLECTION_ID>',
252+
[
253+
{
254+
'$id': sdk.ID.unique(),
255+
'$createdAt': new Date('2024-01-01T00:00:00.000Z').toISOString(),
256+
'$updatedAt': new Date('2024-01-01T00:00:00.000Z').toISOString(),
257+
// ...your attributes
258+
},
259+
{
260+
'$id': sdk.ID.unique(),
261+
'$createdAt': new Date('2024-02-01T00:00:00.000Z').toISOString(),
262+
'$updatedAt': new Date('2024-02-01T00:00:00.000Z').toISOString(),
263+
// ...your attributes
264+
}
265+
]
266+
);
267+
```
268+
```server-python
269+
databases.create_documents(
270+
database_id='<DATABASE_ID>',
271+
collection_id='<COLLECTION_ID>',
272+
documents=[
273+
{
274+
'$id': ID.unique(),
275+
'$createdAt': datetime(2024, 1, 1, tzinfo=timezone.utc).isoformat(),
276+
'$updatedAt': datetime(2024, 1, 1, tzinfo=timezone.utc).isoformat(),
277+
# ...your attributes
278+
},
279+
{
280+
'$id': ID.unique(),
281+
'$createdAt': datetime(2024, 2, 1, tzinfo=timezone.utc).isoformat(),
282+
'$updatedAt': datetime(2024, 2, 1, tzinfo=timezone.utc).isoformat(),
283+
# ...your attributes
284+
}
285+
]
286+
)
287+
```
288+
{% /multicode %}
289+
290+
### Bulk upsert {% #bulk-upsert %}
291+
292+
{% multicode %}
293+
```server-nodejs
294+
await databases.upsertDocuments(
295+
'<DATABASE_ID>',
296+
'<COLLECTION_ID>',
297+
[
298+
{
299+
'$id': '<DOCUMENT_ID_OR_NEW_ID>',
300+
'$createdAt': new Date('2024-01-01T00:00:00.000Z').toISOString(),
301+
'$updatedAt': new Date('2025-01-01T00:00:00.000Z').toISOString(),
302+
// ...your attributes
303+
}
304+
]
305+
);
306+
```
307+
```server-python
308+
databases.upsert_documents(
309+
database_id='<DATABASE_ID>',
310+
collection_id='<COLLECTION_ID>',
311+
documents=[
312+
{
313+
'$id': '<DOCUMENT_ID_OR_NEW_ID>',
314+
'$createdAt': datetime(2024, 1, 1, tzinfo=timezone.utc).isoformat(),
315+
'$updatedAt': datetime(2025, 1, 1, tzinfo=timezone.utc).isoformat(),
316+
# ...your attributes
317+
}
318+
]
319+
)
320+
```
321+
{% /multicode %}
322+
323+
# Common use cases {% #use-cases %}
324+
325+
Custom timestamps are particularly useful in several scenarios:
326+
327+
## Data migration {% #data-migration %}
328+
When migrating existing data from another system, you can preserve the original creation and modification times:
329+
330+
```javascript
331+
// Migrating blog posts with original timestamps
332+
await databases.createDocument(
333+
databaseId,
334+
'blog_posts',
335+
sdk.ID.unique(),
336+
{
337+
'$createdAt': existingPost.originalCreatedAt,
338+
'$updatedAt': existingPost.lastModified,
339+
title: existingPost.title,
340+
content: existingPost.content
341+
}
342+
);
343+
```
344+
345+
## Backdating records {% #backdating %}
346+
For historical data entry or when creating records that represent past events:
347+
348+
```javascript
349+
// Creating a historical financial record
350+
await databases.createDocument(
351+
databaseId,
352+
'transactions',
353+
sdk.ID.unique(),
354+
{
355+
'$createdAt': '2023-12-31T23:59:59.000Z',
356+
'$updatedAt': '2023-12-31T23:59:59.000Z',
357+
amount: 1000,
358+
type: 'year-end-bonus'
359+
}
360+
);
361+
```
362+
363+
## Synchronization {% #synchronization %}
364+
When synchronizing data between systems while maintaining timestamp consistency:
365+
366+
```javascript
367+
// Keeping timestamps in sync across systems
368+
await databases.upsertDocument(
369+
databaseId,
370+
'users',
371+
userId,
372+
{
373+
'$updatedAt': externalSystem.lastModified,
374+
profile: externalSystem.userProfile
375+
}
376+
);
377+
```
378+
379+
{% info title="Timestamp format and usage" %}
380+
- Values must be valid ISO 8601 date-time strings (UTC recommended). Using `toISOString()` (JavaScript) or `datetime.isoformat()` (Python) is a good default.
381+
- You can set either or both attributes as needed. If omitted, Appwrite sets them automatically.
382+
- Custom timestamps work with all document operations: create, update, upsert, and their bulk variants.
383+
{% /info %}
384+

0 commit comments

Comments
 (0)