The Lumar GraphQL API supports patterns that go well beyond single-resource lookups. Understanding these patterns lets you fetch exactly the data you need in fewer requests and express complex filtering logic. This page covers production patterns used by real API clients. ## Multi-root queries GraphQL allows a single request to call multiple top-level resolvers at once. Instead of making four sequential HTTP requests to load a project settings screen, you can combine them into one query. All resolvers execute in parallel on the server and the results arrive in a single response. :::tip Multi-root queries are the single most effective way to eliminate loading waterfalls in UI applications. Use them whenever you need data from more than one top-level field on the initial render. ::: ```graphql query GetProjectSettings($projectId: ObjectID!, $accountId: ObjectID!) { getProject(id: $projectId) { id name primaryDomain } getAccount(id: $accountId) { id maxCrawlRate subscription { plan { code } } } getScheduleFrequencies { code name } getUserAgents { code name isMobile } } ``` **Variables:** ```json { "projectId": "TjAwN1Byb2plY3Q2MjAyMw", "accountId": "TjAwN0FjY291bnQ3MTU" } ``` **Response:** ```json { "data": { "getProject": { "id": "TjAwN1Byb2plY3Q2MjAyMw", "name": "Lumar Docs", "primaryDomain": "https://www.lumar.io/" }, "getAccount": { "id": "TjAwN0FjY291bnQ3MTU", "maxCrawlRate": 5, "subscription": { "plan": { "code": "enterprise" } } }, "getScheduleFrequencies": [ { "code": "Daily", "name": "Daily" }, { "code": "Weekly", "name": "Weekly" } ], "getUserAgents": [ { "code": "desktop", "name": "Desktop Chrome", "isMobile": false }, { "code": "mobile", "name": "Mobile Chrome", "isMobile": true } ] } } ``` The response contains `getProject`, `getAccount`, `getScheduleFrequencies`, and `getUserAgents` side-by-side in `data`. There is no overhead beyond a single round trip. ## Field aliasing GraphQL aliases let you call the same field more than once in a single query, each time with different arguments, and map each result to a distinct key in the response. This is commonly used to fetch multiple "views" of the same connection without multiple requests. The example below fetches two separate crawl lists from a single project: the most recently created crawl (regardless of status) and the five most recently finished crawls. ```graphql query GetProjectCrawlsSummary($projectId: ObjectID!) { getProject(id: $projectId) { id lastCrawl: crawls(first: 1, orderBy: [{ field: createdAt, direction: DESC }]) { nodes { id statusEnum finishedAt } } recentFinished: crawls( first: 5 filter: { statusEnum: { eq: Finished } } orderBy: [{ field: finishedAt, direction: DESC }] ) { nodes { id finishedAt } } } } ``` **Variables:** ```json { "projectId": "TjAwN1Byb2plY3Q2MjAyMw" } ``` **Response:** ```json { "data": { "getProject": { "id": "TjAwN1Byb2plY3Q2MjAyMw", "lastCrawl": { "nodes": [ { "id": "TjAwNUNyYXdsMTU4MzI0Ng", "statusEnum": "Crawling", "finishedAt": null } ] }, "recentFinished": { "nodes": [ { "id": "TjAwNUNyYXdsMTU4MzI0NQ", "finishedAt": "2025-03-20T14:30:00.000Z" }, { "id": "TjAwNUNyYXdsMTU4MzI0NA", "finishedAt": "2025-03-13T09:15:00.000Z" } ] } } } } ``` Without aliases, a second call to `crawls` in the same selection set would be a syntax error. With aliases (`lastCrawl:` and `recentFinished:`), both calls are valid and their results are returned under those keys. ## Nested filtering with boolean logic The `filter` argument accepts `_or`, `_and`, and `_not` arrays that can be nested arbitrarily. This lets you express conditions such as "give me all crawls that are currently running, queued, or paused" without fetching everything and filtering client-side. ### Using `_or` to match any of several enum values ```graphql query GetActiveCrawls($projectId: ObjectID!) { getProject(id: $projectId) { id crawls( first: 20 filter: { _or: [ { statusEnum: { eq: Crawling } } { statusEnum: { eq: Queued } } { statusEnum: { eq: Paused } } ] } orderBy: [{ field: createdAt, direction: DESC }] ) { nodes { id statusEnum createdAt } totalCount } } } ``` **Variables:** ```json { "projectId": "TjAwN1Byb2plY3Q2MjAyMw" } ``` **Response:** ```json { "data": { "getProject": { "id": "TjAwN1Byb2plY3Q2MjAyMw", "crawls": { "nodes": [ { "id": "TjAwNUNyYXdsMTU4MzI0Ng", "statusEnum": "Crawling", "createdAt": "2025-03-27T08:00:00.000Z" }, { "id": "TjAwNUNyYXdsMTU4MzI0NQ", "statusEnum": "Queued", "createdAt": "2025-03-26T22:00:00.000Z" } ], "totalCount": 2 } } } } ``` :::tip For matching multiple values of the same enum field, the `in` predicate is more concise than `_or`. Use `_or` when the conditions involve different fields. ::: ### Using `_and` to combine a status filter with a date range ```graphql query GetRecentFinishedCrawls($projectId: ObjectID!) { getProject(id: $projectId) { id crawls( first: 10 filter: { _and: [ { statusEnum: { eq: Finished } } { finishedAt: { ge: "2025-01-01T00:00:00Z" } } ] } orderBy: [{ field: finishedAt, direction: DESC }] ) { nodes { id statusEnum finishedAt } totalCount } } } ``` **Variables:** ```json { "projectId": "TjAwN1Byb2plY3Q2MjAyMw" } ``` **Response:** ```json { "data": { "getProject": { "id": "TjAwN1Byb2plY3Q2MjAyMw", "crawls": { "nodes": [ { "id": "TjAwNUNyYXdsMTU4MzI0NQ", "statusEnum": "Finished", "finishedAt": "2025-03-20T14:30:00.000Z" } ], "totalCount": 1 } } } } ``` The `_and` array requires every condition to be true. Combining a status check with a date boundary is a common pattern for auditing or reporting workflows. See the [Filtering guide](filtering) for the full set of available predicates for each field type. ## Inline arguments on nested fields Connection fields anywhere in the query tree accept their own `first`, `after`, `filter`, and `orderBy` arguments. You do not have to fetch the parent first and then issue a follow-up query for child data. The example below loads a paginated list of projects and, for each project, the most recently finished crawl -- all in a single request. ```graphql query GetAccountProjectsWithLatestCrawl($accountId: ObjectID!) { getAccount(id: $accountId) { id projects(first: 20, orderBy: [{ field: createdAt, direction: DESC }]) { nodes { id name primaryDomain lastCrawlStatus crawls(first: 1, orderBy: [{ field: finishedAt, direction: DESC }]) { nodes { id finishedAt statusEnum } } } pageInfo { hasNextPage endCursor } totalCount } } } ``` **Variables:** ```json { "accountId": "TjAwN0FjY291bnQ3MTU" } ``` **Response:** ```json { "data": { "getAccount": { "id": "TjAwN0FjY291bnQ3MTU", "projects": { "nodes": [ { "id": "TjAwN1Byb2plY3Q2MjAyMw", "name": "Lumar Docs", "primaryDomain": "https://www.lumar.io/", "lastCrawlStatus": "Finished", "crawls": { "nodes": [ { "id": "TjAwNUNyYXdsMTU4MzI0NQ", "finishedAt": "2025-03-20T14:30:00.000Z", "statusEnum": "Finished" } ] } } ], "pageInfo": { "hasNextPage": false, "endCursor": "MjA" }, "totalCount": 1 } } } } ``` :::warning Nesting connections increases query cost. Keep `first` values small on nested connections — fetching 20 projects each with their own `crawls` connection can return a large amount of data quickly. Prefer smaller page sizes and paginate if you need more. ::: ## Requesting only what you need Fetching fewer fields and shallower nesting makes queries faster and reduces the payload size. This matters both for latency and for staying within the [rate limits](rate-limits). ### Bloated query — slow and returns more data than needed ```graphql query GetProjectData($projectId: ObjectID!) { getProject(id: $projectId) { id name primaryDomain lastCrawlStatus createdAt updatedAt crawls(first: 50) { nodes { id statusEnum finishedAt createdAt crawlUrlsTotal crawlSegments(first: 100) { nodes { segmentId segmentVersion createdAt generatedAt failedAt failureReason } totalCount } } totalCount } } } ``` **Variables:** ```json { "projectId": "TjAwN1Byb2plY3Q2MjAyMw" } ``` This query requests 50 crawls, each with 100 crawl segments and 6 fields per segment — up to 5,000 segment objects in a single response. Most callers only need a handful of fields to render a dashboard or trigger a workflow. ### Lean query — fast and focused ```graphql query GetProjectCrawlStatus($projectId: ObjectID!) { getProject(id: $projectId) { id name lastCrawlStatus crawls(first: 5, orderBy: [{ field: createdAt, direction: DESC }]) { nodes { id statusEnum finishedAt } totalCount } } } ``` **Variables:** ```json { "projectId": "TjAwN1Byb2plY3Q2MjAyMw" } ``` **Response:** ```json { "data": { "getProject": { "id": "TjAwN1Byb2plY3Q2MjAyMw", "name": "Lumar Docs", "lastCrawlStatus": "Finished", "crawls": { "nodes": [ { "id": "TjAwNUNyYXdsMTU4MzI0NQ", "statusEnum": "Finished", "finishedAt": "2025-03-20T14:30:00.000Z" } ], "totalCount": 12 } } } } ``` This version requests 5 crawls with 3 fields each and no nested connection. It returns in a fraction of the time. :::tip **Rules of thumb:** - Request only the fields you will actually use. - Keep `first` / `last` values as small as your use case allows. - Avoid nesting connection fields more than two levels deep unless necessary. - If you need large volumes of URL-level data, use [report downloads](generate-report-downloads) instead of paginating `crawlUrls`. :::