Pattern db.tenant.mixin e db.reseller.mixin
Panoramica
I mixin database sono il componente fondamentale per l'accesso ai dati nella piattaforma. Ogni mixin seleziona automaticamente il database corretto in base al contesto della richiesta, fornendo operazioni CRUD standardizzate. Esistono tre mixin, uno per ciascun livello di dati.
TenantDbMixin
Usato dalla maggior parte dei servizi. Seleziona il database t_{tenantId} estraendo il tenantId da ctx.meta.tenantId.
const TenantDbMixin = require("../mixins/db.tenant.mixin.js");
module.exports = {
name: "products",
mixins: [TenantDbMixin("products")],
// Le azioni CRUD (list, find, get, create, update, remove) sono ereditate
};
Metodi disponibili nei servizi che usano questo mixin:
_getCollection(ctx)-- Ritorna la collezione MongoDB per il tenant correntegetDb(ctx)-- Ritorna il riferimento al databaset_{tenantId}encodeID(id)-- Converte una stringa inObjectIdse valida
ResellerDbMixin
Usato dai servizi che operano a livello reseller (cross-tenant). Seleziona il database r_{resellerCode} cercando il codice in ctx.params.resellerCode, ctx.meta.resellerCode o ctx.meta.user.resellerCode.
const ResellerDbMixin = require("../mixins/db.reseller.mixin.js");
module.exports = {
name: "manutenzioni",
mixins: [ResellerDbMixin("interventions")],
};
A differenza del TenantDbMixin, se il resellerCode non e presente nel contesto il mixin lancia un errore esplicito anziche fare fallback su un database generico.
PlatformDbMixin
Usato per dati condivisi della piattaforma. Opera sempre sul database pos_platform, senza bisogno di tenantId o resellerCode.
const PlatformDbMixin = require("../mixins/db.platform.mixin.js");
module.exports = {
name: "tenant-management",
mixins: [PlatformDbMixin("tenants")],
};
Il PlatformDbMixin disabilita la cache di default (cache: false su tutte le azioni di lettura) perche i dati platform sono amministrativi e devono essere sempre aggiornati. Fornisce anche un oggetto this.adapter compatibile con il pattern moleculer-db per i servizi che ne dipendono.
Azioni CRUD Ereditate
Tutti e tre i mixin forniscono le stesse azioni base:
| Azione | Descrizione |
|---|---|
list | Lista paginata con page, pageSize, sort, query |
find | Ricerca con query, limit, offset, sort |
count | Conteggio documenti con query |
get | Singolo documento per id |
create | Inserimento con createdAt/updatedAt automatici |
update | Aggiornamento parziale per id con updatedAt automatico |
remove | Eliminazione per id |
Caching e Gotcha Importante
Il TenantDbMixin e il ResellerDbMixin includono cache keys che incorporano #tenantId o #resellerCode per garantire isolamento. Tuttavia, quando un servizio sovrascrive un'azione del mixin, Moleculer esegue un deep merge delle proprieta.
Questo significa che le cache keys del mixin persistono anche nell'azione sovrascritta. Se l'azione custom esegue scritture raw (insertMany, updateMany) senza invalidare la cache, i dati restano stale.
Soluzione: aggiungere sempre cache: false alle azioni custom che bypassano il CRUD del mixin, oppure chiamare this.broker.cacher.clean("nomeservizio.**") dopo le scritture raw.
actions: {
importBulk: {
cache: false, // CRITICO: evita dati stale
async handler(ctx) {
const col = await this._getCollection(ctx);
await col.insertMany(ctx.params.items);
await this.broker.cacher.clean(`${this.name}.**`);
return { imported: ctx.params.items.length };
}
}
}
FAQ
D: Devo sempre usare un mixin per accedere al database? R: Si. I mixin garantiscono l'isolamento multi-tenant, il pool di connessioni condiviso e la cache corretta. Accedere direttamente a MongoDB bypassa tutte queste protezioni.
D: Come accedo a due collezioni diverse nello stesso servizio?
R: Un servizio puo definire un solo mixin con una collezione. Per accedere a una seconda collezione, utilizzare this.mongoClient.db(...) manualmente oppure chiamare un altro servizio via ctx.call().
D: Perche findOneAndUpdate ritorna il documento direttamente?
R: Con MongoDB driver v6, findOneAndUpdate e findOneAndDelete ritornano il documento direttamente (non { value: doc }). Il PlatformDbMixin gestisce entrambi i formati per compatibilita.
Vedi Anche
- Multi-Tenancy -- Architettura multi-tenant e naming database
- API Ordini -- Esempio di servizio che usa TenantDbMixin
- Panoramica Architettura -- Visione d'insieme della piattaforma