Skip to content

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;
}

Part of Nimbu, built by Zenjoy.