Deploy your first customer portal →
SuitePortal/NetSuite ORM

Relations & Include

Use include to JOIN related records in a single query.

SuitePortal introspects relationships between records and lets you include related data in your queries using include, similar to Prisma's relation loading.

How It Works

When you pass include to findMany or findFirst, SuitePortal generates a LEFT JOIN and returns nested objects:

const orders = await ns.salesorder.findMany({
  select: { id: true, tranid: true },
  include: { entity: true },
  take: 10,
});
SELECT salesorder.id, salesorder.tranid,
       entity.id AS entity__id,
       entity.companyname AS entity__companyname,
       entity.email AS entity__email
FROM salesorder
LEFT JOIN customer entity ON salesorder.entity = entity.id
[
  {
    id: 1,
    tranid: 'SO-001',
    entity: {
      id: 42,
      companyname: 'Acme Corp',
      email: 'hello@acme.com',
    },
  },
  // ...
]

Selective Include

By default, include: { entity: true } fetches all fields from the related record. You can narrow it with select:

const orders = await ns.salesorder.findMany({
  select: { id: true, tranid: true },
  include: {
    entity: { select: { companyname: true, email: true } },
  },
});

This only fetches id, companyname, and email from the customer record (id is always included).

Null Handling

When a record has no matching relation (e.g., a sales order with no customer), the included relation is null:

{
  id: 2,
  tranid: 'SO-002',
  entity: null,  // No matching customer
}

Supported Relation Types

Relation TypeExampleSupported
Many-to-oneSales order → Customer (via entity field)Yes
One-to-manyCustomer → Sales ordersNot yet

One-to-many relations (reverse lookups) require a separate query or subquery and are planned for a future release. Only many-to-one include is supported today.

Finding Available Relations

Relations are defined in your schema. After running suiteportal introspect, check .suiteportal/schema.json to see what relations were discovered for each record:

.suiteportal/schema.json
{
  "salesorder": {
    "relations": {
      "entity": {
        "type": "many-to-one",
        "target": "customer",
        "foreignKey": "entity"
      }
    }
  }
}

The key name (e.g., entity) is what you use in include.

Combining with Other Options

include works alongside where, orderBy, take, and skip:

const orders = await ns.salesorder.findMany({
  where: { tranid: { startsWith: 'SO' } },
  select: { id: true, tranid: true },
  include: { entity: true },
  orderBy: { tranid: 'desc' },
  take: 25,
});

On this page