Přehled
{productName} nabízí tři metody pro detekci a sledování změn ve vašich datech. Každá metoda má jiné možnosti a je vhodná pro specifické případy použití.
Výběr správné metody
- updatedAt — Jednoduché periodické synchronizace bez sledování odstranění
- Changes API — Kompletní historie změn s dotazováním
- Webhooks — Oznámení v reálném čase s automatickým doručováním
Porovnání metod
Porovnejte tři metody detekce změn a vyberte tu nejvhodnější pro váš případ použití
card: updatedAt
**Výhody**
- Jednoduchá implementace
- Nízká režie - používá standardní filtry dotazů
- Dobré pro periodické synchronizace (hodinové, denní)
**Omezení**
- Nedetekuje odstranění
- Vyžaduje dotazování
- Může zmeškat rychlé změny, pokud je interval dotazování příliš dlouhý
**Nejlepší pro:** Jednoduché integrace, kde jsou odstranění vzácná nebo nejsou kritická
card: Changes API
**Výhody**
- Zachycuje všechny operace (vytvoření, aktualizace, odstranění)
- Sledování verzí se sekvenčními ID
- Spolehlivé - nezmešká žádné změny
- Může sledovat více entit
**Omezení**
- Vyžaduje dotazování
- Je třeba udržovat ID poslední verze
- Zpoždění na základě intervalu dotazování
**Nejlepší pro:** Robustní integrace vyžadující kompletní historii změn a sledování odstranění
card: Webhooks
**Výhody**
- Oznámení v reálném čase (do 5 sekund)
- Není nutné dotazování
- Dávkové doručování (až 100 změn)
- Vestavěný mechanismus opakování
- Podporuje filtrování
**Omezení**
- Vyžaduje veřejně přístupný koncový bod
- Musí zvládnout spolehlivost webhooků
- Složitější nastavení
**Nejlepší pro:** Integrace v reálném čase vyžadující okamžitou akci při změnách dat
Metoda 1: Použití updatedAt [badge:Simple|info]
Sledujte změny pomocí pole časového razítka updatedAt, které je k dispozici u všech entit
**Důležité omezení:**
Metoda `updatedAt` nedetekuje odstranění. Pokud potřebujete sledovat odstraněné záznamy, použijte místo toho Changes API nebo Webhooks.
Dotaz na produkty aktualizované od poslední synchronizace
Načtěte všechny produkty, které byly upraveny po určitém časovém razítku
GET /c/{companyId}/products?filter=updatedAt > '2025-11-14T10:00:00Z'&limit=100
// Response
{
"data": [
{
"id": "prod-123",
"name": "Aktualizovaný produkt",
"price": 99.99,
"updatedAt": "2025-11-14T10:15:30Z"
}
// ... další produkty
]
}
Sledování času poslední synchronizace (správná metoda)
Uložte časové razítko z posledního načteného záznamu, abyste se vyhnuli zmeškání změn
// Inicializujte časovým razítkem z poslední synchronizace
// Pro první synchronizaci použijte časové razítko v minulosti nebo null
let lastSyncTime = '2025-01-01T00:00:00Z';
// Při každé synchronizaci
const url = `/c/{companyId}/products?filter=${encodeURIComponent(
`updatedAt > '${lastSyncTime}'`
)}&limit=100&sort=updatedAt`;
const response = await fetch(url);
const { data } = await response.json();
if (data.length > 0) {
// Zpracujte změněné produkty
data.forEach(product => {
console.log('Aktualizováno:', product.id, product.updatedAt);
});
// ✅ SPRÁVNĚ: Použijte updatedAt z posledního záznamu
lastSyncTime = data[data.length - 1].updatedAt;
// ❌ ŠPATNĚ: Nikdy nepoužívejte new Date().toISOString()
// To může zmeškat změny z důvodu:
// - Čas mezi dotazem a voláním new Date()
// - Rozdílné hodiny mezi klientem a serverem
}
⚠️ Kritické: Synchronizace času
**Nikdy nepoužívejte `new Date().toISOString()` pro lastSyncTime!**
Tento přístup má dva kritické problémy:
1. **Stav závodu:** Mezi načtením dat a voláním `new Date()` může dojít ke změnám, což způsobí, že tyto změny zmeškáte při další synchronizaci.
2. **Rozdílné hodiny:** Hodiny klienta a serveru nemusí být synchronizovány. Pokud jsou hodiny klienta napřed, zmeškáte změny. Pokud jsou pozadu, získáte duplicitní data.
✅ Vždy používejte hodnotu `updatedAt` z posledního záznamu vráceného serverem.
Metoda 2: Použití Changes API [badge:Complete|success]
Sledujte všechny změny včetně odstranění pomocí protokolu změn se sledováním verzí
Klíčové výhody
- Zachycuje operace vytvoření, aktualizace a odstranění
- Sekvenční ID verzí pro spolehlivé sledování
- Dotaz na více entit v jednom požadavku
- Žádná ztráta dat ani při dlouhých intervalech dotazování
Získání nedávných změn pro produkty
Načtěte všechny změny (včetně odstranění) pro produkty se sledováním verzí
GET /c/{companyId}/changes?filter=entity = 'products' and id > 100&limit=100
// Response
{
"data": [
{
"id": 101, // číslo verze
"entity": "products",
"rowId": "prod-123",
"operation": "update",
"changeSetId": null,
"createdAt": "2025-11-14T10:15:30Z"
},
{
"id": 102,
"entity": "products",
"rowId": "prod-456",
"operation": "delete",
"changeSetId": null,
"createdAt": "2025-11-14T10:16:45Z"
}
]
}
Dotazování na změny se sledováním verzí
Nepřetržitě se dotazujte na nové změny pomocí posledního známého ID verze
// Uložte poslední zpracovanou verzi
let lastVersionId = 0;
async function pollForChanges() {
const filter = encodeURIComponent(
`entity = 'products' and id > ${lastVersionId}`
);
const response = await fetch(
`/c/{companyId}/changes?filter=${filter}&limit=100&sort=id`
);
const { data } = await response.json();
if (data.length > 0) {
// Zpracujte změny
for (const change of data) {
console.log(
`Změna #${change.id}: ${change.operation} na ${change.rowId}`
);
if (change.operation === 'delete') {
// Zpracujte odstranění
console.log('Produkt odstraněn:', change.rowId);
} else {
// Načtěte aktualizovaný produkt
const product = await fetch(
`/c/{companyId}/products/${change.rowId}`
).then(r => r.json());
console.log('Produkt aktualizován:', product);
}
}
// Aktualizujte ID poslední verze
lastVersionId = data[data.length - 1].id;
}
}
// Dotazujte se každých 30 sekund
setInterval(pollForChanges, 30000);
Získání změn pro více entit
Monitorujte změny napříč různými typy entit
const filter = encodeURIComponent(
`(entity = 'products' OR entity = 'categories') and id > ${lastVersionId}`
);
const response = await fetch(
`/c/{companyId}/changes?filter=${filter}&limit=100&sort=id`
);
const { data } = await response.json();
// Seskupte změny podle entity
const changesByEntity = data.reduce((acc, change) => {
if (!acc[change.entity]) acc[change.entity] = [];
acc[change.entity].push(change);
return acc;
}, {});
console.log('Změněné produkty:', changesByEntity.products?.length || 0);
console.log('Změněné kategorie:', changesByEntity.categories?.length || 0);
Metoda 3: Použití Webhooks [badge:Real-time|warning]
Získejte automatická oznámení do 5 sekund od jakékoli změny dat
**Funkce v reálném čase**
- Oznámení doručena do 5 sekund od změn
- Dávkové doručování (až 100 změn na webhook)
- Filtrování podle typu entity (konkrétní entita nebo všechny entity)
- Filtrování podle podmínek řádků (např. "price > 100")
- Filtrování podle změněných sloupců (např. ["price", "status"])
- Automatické opakování s exponenciálním zpožděním
Registrace Webhooku pro produkty
Získejte automatická oznámení při změně produktů
POST /c/{companyId}/hooks
Content-Type: application/json
{
"entity": "products",
"url": "https://your-api.com/webhooks/products",
"action": "webhook"
}
// Váš koncový bod webhooku obdrží:
{
"hookId": "hook-123",
"tenantId": "tenant-789",
"organisationId": "{companyId}",
"changeSetId": null,
"changes": [
{
"id": "change-001",
"entity": "products",
"operation": "update",
"rowId": "prod-123",
"changeSetId": null
}
],
"timestamp": "2025-11-14T10:30:00.000Z"
}
Příklad obslužného programu Webhooku
Zpracování příchozích oznámení webhooku
// Obslužný program webhooku Express.js
app.post('/webhooks/products', async (req, res) => {
const { changes } = req.body;
for (const change of changes) {
console.log(
`Webhook: ${change.operation} na ${change.rowId}`
);
if (change.operation === 'delete') {
// Zpracujte odstranění produktu
await deleteProductInMySystem(change.rowId);
} else {
// Načtěte a zpracujte aktualizovaný produkt
const product = await fetch(
`https://api.productsync.com/c/{companyId}/products/${change.rowId}`,
{
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
}
}
).then(r => r.json());
await updateProductInMySystem(product);
}
}
// Vždy odpovězte kódem 200 pro potvrzení přijetí
res.status(200).json({ received: true });
});
Webhook pro konkrétní entitu
Omezte oznámení na jeden typ entity
POST /c/{companyId}/hooks
Content-Type: application/json
{
"entity": "products",
"url": "https://your-api.com/webhooks/products",
"action": "webhook"
}
// Tento webhook spustí pouze změny produktů
// Změny kategorií, jednotek atd. budou ignorovány
Webhook pro všechny entity
Monitorujte všechny změny entit v jednom webhooku
POST /c/{companyId}/hooks
Content-Type: application/json
{
"entity": null,
"url": "https://your-api.com/webhooks/all-changes",
"action": "webhook"
}
// Tento webhook bude přijímat oznámení pro VŠECHNY typy entit
// Produkty, kategorie, jednotky, zákazníci, objednávky atd.
Webhook s filtrem podmínky řádku
Získejte oznámení pouze v případě, že řádky splňují specifické podmínky
POST /c/{companyId}/hooks
Content-Type: application/json
{
"entity": "products",
"url": "https://your-api.com/webhooks/expensive-products",
"action": "webhook",
"filter": "price > 100 AND status = 'active'"
}
// Webhooky obdržíte pouze v případě, že:
// - Entita je 'products'
// - A cena produktu je vyšší než 100
// - A stav produktu je 'active'
Webhook s filtrem sloupců
Spusťte pouze při změně konkrétních sloupců
POST /c/{companyId}/hooks
Content-Type: application/json
{
"entity": "products",
"url": "https://your-api.com/webhooks/product-pricing",
"action": "webhook",
"columns": ["price", "discount", "tax"]
}
// Webhook se spustí pouze při změně ceny, slevy nebo daně
// Změny názvu, popisu atd. budou ignorovány
Webhook s kombinovanými filtry
Kombinujte entity, podmínky řádků a filtry sloupců
POST /c/{companyId}/hooks
Content-Type: application/json
{
"entity": "products",
"url": "https://your-api.com/webhooks/premium-product-pricing",
"action": "webhook",
"filter": "price > 100",
"columns": ["price", "status"]
}
// Trojité filtrování:
// 1. Pouze entita 'products'
// 2. Pouze pokud je cena > 100
// 3. Pouze při změně sloupců cena nebo stav
** Možnosti filtrování webhooku**
**1. Filtrování entity**
Nastavte `entity` pro omezení oznámení na konkrétní typ entity (např. "products", "categories"). Použijte `null` pro příjem oznámení pro všechny entity.
**2. Filtrování podmínky řádku**
Použijte `filter` s klauzulemi where podobnými SQL pro spuštění webhooků pouze v případě, že řádky splňují specifické podmínky (např. "price > 100 AND status = 'active'").
**3. Filtrování změny sloupce**
Zadejte pole `columns` pro spuštění pouze při změně těchto konkrétních sloupců. Ideální pro monitorování aktualizací cen, změn stavu atd.
**4. Kombinované filtrování**
Kombinujte všechny tři filtry pro přesné ovládání: typ entity + podmínky řádků + změny sloupců. Tím se minimalizují zbytečná volání webhooků a zpracování.
Poznámka: Kompletní dokumentaci webhooků včetně logiky opakování, možností filtrování a příkladů datové části naleznete v [navigate:/devdoc/webhooks|Dokumentaci k Webhookům].
Doporučené postupy
Kdy použít updatedAt
- Jednoduché integrace s periodickými synchronizacemi (hodinové, denní)
- Pokud jsou odstranění zpracovávána samostatně nebo nejsou potřeba
- Nízkofrekvenční aktualizace dat
- Rychlé prototypy a MVP
Kdy použít Changes API
- Potřeba sledovat všechny operace včetně odstranění
- Vytváření kompletního systému synchronizace dat
- Udržování auditní stopy změn
- Pokud není k dispozici infrastruktura webhooků
- Dávkové zpracování změn
Kdy použít Webhooks
- Potřeba aktualizací dat v reálném čase nebo téměř v reálném čase
- Spouštění okamžitých akcí při změnách dat
- Automatické udržování synchronizace externích systémů
- Pokud můžete udržovat veřejně přístupný koncový bod
- Vysokofrekvenční změny dat vyžadující rychlou odezvu
**Hybridní přístup:**
Zvažte použití webhooků pro aktualizace v reálném čase a Changes API jako zálohu pro zachycení všech zmeškaných změn během výpadků nebo selhání webhooků. To poskytuje to nejlepší z obou světů: aktualizace v reálném čase se zaručenou úplností.