Recipes
These examples are generic patterns. They avoid project-specific details but mirror the shape of real Nimbu work.
Lookup Or Create
js
async function getOrCreateCustomer(email, attrs = {}) {
const existing = await new Nimbu.Query(Nimbu.Customer)
.equalTo('email', email)
.first();
if (existing) return existing;
const customer = new Nimbu.Customer({
email,
...attrs
});
return customer.save();
}Update A Relation From Ids
js
async function replaceEditors(groupId, nextCustomerIds) {
const group = await new Nimbu.Query('groups').get(groupId);
await group.fetchWithInclude('editors');
const editors = group.relation('editors');
const currentIds = editors.list().map((customer) => customer.id);
for (const id of currentIds) {
if (!nextCustomerIds.includes(id)) {
editors.remove(new Nimbu.Object('customers', { id }));
}
}
for (const id of nextCustomerIds) {
if (!currentIds.includes(id)) {
editors.add(new Nimbu.Object('customers', { id }));
}
}
await group.save();
}Scheduled Sync State In Cloud Code
Store integration progress in a channel entry. Schedule jobs with ids, not full objects.
js
Nimbu.Cloud.job('sync_article', async ({ params }) => {
const state = await new Nimbu.Query('sync_states').get(params.stateId);
try {
const article = await new Nimbu.Query('articles').get(state.get('article_id'));
await sendToExternalSystem(article);
state.set({
status: 'done',
finished_at: new Date()
});
} catch (error) {
state.set({
status: 'failed',
error_message: error.message
});
}
await state.save();
});
async function scheduleArticleSync(articleId) {
const state = await new Nimbu.Object('sync_states', {
article_id: articleId,
status: 'queued'
}).save();
await Nimbu.Cloud.schedule('sync_article', { stateId: state.id }, {});
}Batch Export
js
async function exportPaidOrders() {
const query = new Nimbu.Query(Nimbu.Order);
query.equalTo('status', 'paid');
query.doesNotExist('exported_at');
await query.eachBatch(async (orders) => {
for (const order of orders) {
await exportOrder(order);
order.set('exported_at', new Date());
await order.save();
}
}, { batchSize: 50 });
}Customer-Visible Query In Cloud Code
Use useACL when server-side code should return the same view a customer would get.
js
Nimbu.Cloud.get('/api/articles', async (request, response) => {
const articles = await new Nimbu.Query('articles')
.equalTo('published', true)
.descending('published_at')
.limit(20)
.find({ useACL: true });
response.json(articles.map((article) => article.toJSON()));
});Attach A Generated File
js
async function attachPdf(entryId, pdfBase64) {
const entry = await new Nimbu.Query('contracts').get(entryId);
entry.set('document', new Nimbu.File('contract.pdf', {
base64: pdfBase64
}));
return entry.save();
}Update ACLs Before Save
js
function allowOwnerOnly(entry, customerId) {
const acl = new Nimbu.ACL();
acl.setPublicReadAccess(false);
acl.allowRead(customerId, true);
acl.allowUpdate(customerId, true);
entry.setACL(acl);
return entry;
}