# Filtering & Querying

Most API endpoints support query parameters for filtering, and all
query result endpoints support pagination. This guide covers the
common patterns.

## Filtering Entities

Structure endpoints like nodes, members, and sections support query
parameters to narrow down results.

<CodeTabs>
```csharp title="C#"
// Get nodes within a coordinate range
var filtered = await client.Job.Structure.Nodes.GetAsync(
    config =>
    {
        config.QueryParameters.MinX = 0;
        config.QueryParameters.MaxX = 100;
        config.QueryParameters.Limit = 50;
    });
```

```python title="Python"
filtered = await client.job.structure.nodes.get(
    min_x=0, max_x=100, limit=50)
```

```bash title="curl"
curl "http://localhost:34560/api/v1/job/structure/nodes?MinX=0&MaxX=100&Limit=50"
```
</CodeTabs>

## Getting a Single Entity

Access any entity by its Id using the indexer (C#) or `by_id`
(Python):

<CodeTabs>
```csharp title="C#"
var node = await client.Job.Structure.Nodes[1].GetAsync();
Console.WriteLine($"Node {node.Id}: ({node.X}, {node.Y}, {node.Z})");
```

```python title="Python"
node = await client.job.structure.nodes.by_id(1).get()
print(f"Node {node.id}: ({node.x}, {node.y}, {node.z})")
```

```bash title="curl"
curl http://localhost:34560/api/v1/job/structure/nodes/1
```
</CodeTabs>

## Querying Analysis Results

After running an analysis, query endpoints return results in a flat,
efficient format. All query endpoints support optional filters for
load case and entity key.

### Node Reactions

<CodeTabs>
```csharp title="C#"
var result = await client.Job.Query.Analysis.Static.NodeReactions.GetAsync();

foreach (var r in result.Results)
{
    Console.WriteLine($"Case {r.LoadCase}, Node {r.Node}: " +
        $"Fx={r.Fx}, Fy={r.Fy}, Fz={r.Fz}");
}
```

```python title="Python"
result = await client.job.query.analysis.static.node_reactions.get()

for r in result.results:
    print(f"Case {r.load_case}, Node {r.node}: "
          f"Fx={r.fx}, Fy={r.fy}, Fz={r.fz}")
```

```bash title="curl"
curl http://localhost:34560/api/v1/job/query/analysis/static/node-reactions
```
</CodeTabs>

### Filtering by Load Case and Node

Filter values use **SG list format** — a string of comma-separated Ids
and dash-separated ranges (e.g. `"1,3-7,10"`). Pass an empty string
or omit the parameter to return all results.

<CodeTabs>
```csharp title="C#"
var result = await client.Job.Query.Analysis.Static.NodeDisplacements
    .GetAsync(config =>
    {
        config.QueryParameters.LoadCases = "1,3";
        config.QueryParameters.Nodes = "10-12";
    });
```

```python title="Python"
result = await client.job.query.analysis.static.node_displacements.get(
    load_cases="1,3", nodes="10-12")
```

```bash title="curl"
curl "http://localhost:34560/api/v1/job/query/analysis/static/node-displacements?loadCases=1,3&nodes=10-12"
```
</CodeTabs>

### Member Intermediate Forces

Grouped results like member forces use a columnar layout — the parent
object contains the case and member keys, with force values as parallel
arrays indexed by station.

<CodeTabs>
```csharp title="C#"
var result = await client.Job.Query.Analysis.Static.MemberIntermediateForces
    .GetAsync(config =>
    {
        config.QueryParameters.Members = "1";
    });

foreach (var m in result.Results)
{
    Console.WriteLine($"Case {m.LoadCase}, Member {m.Member}:");
    for (int i = 0; i < m.Station.Length; i++)
    {
        Console.WriteLine($"  Station {m.Station[i]}: " +
            $"Fx={m.Fx[i]}, Fy={m.Fy[i]}, Mz={m.Mz[i]}");
    }
}
```

```python title="Python"
result = await client.job.query.analysis.static.member_intermediate_forces.get(
    members="1")

for m in result.results:
    print(f"Case {m.load_case}, Member {m.member}:")
    for i in range(len(m.station)):
        print(f"  Station {m.station[i]}: "
              f"Fx={m.fx[i]}, Fy={m.fy[i]}, Mz={m.mz[i]}")
```

```bash title="curl"
curl "http://localhost:34560/api/v1/job/query/analysis/static/member-intermediate-forces?members=1"
```
</CodeTabs>

### Buckling Load Factors

<CodeTabs>
```csharp title="C#"
var result = await client.Job.Query.Analysis.Buckling.LoadFactors.GetAsync();

foreach (var b in result.Results)
{
    Console.WriteLine($"Case {b.LoadCase}, Mode {b.Mode}: " +
        $"Factor={b.LoadFactor}, Tolerance={b.Tolerance}");
}
```

```python title="Python"
result = await client.job.query.analysis.buckling.load_factors.get()

for b in result.results:
    print(f"Case {b.load_case}, Mode {b.mode}: "
          f"Factor={b.load_factor}, Tolerance={b.tolerance}")
```

```bash title="curl"
curl http://localhost:34560/api/v1/job/query/analysis/buckling/load-factors
```
</CodeTabs>

### Natural Frequencies

<CodeTabs>
```csharp title="C#"
var result = await client.Job.Query.Analysis.Dynamic.NaturalFrequencies
    .GetAsync();

foreach (var f in result.Results)
{
    Console.WriteLine($"Case {f.LoadCase}, Mode {f.Mode}: " +
        $"{f.NaturalFrequency} Hz (period {f.NaturalPeriod}s)");
}
```

```python title="Python"
result = await client.job.query.analysis.dynamic.natural_frequencies.get()

for f in result.results:
    print(f"Case {f.load_case}, Mode {f.mode}: "
          f"{f.natural_frequency} Hz (period {f.natural_period}s)")
```

```bash title="curl"
curl http://localhost:34560/api/v1/job/query/analysis/dynamic/natural-frequencies
```
</CodeTabs>

### Steel Design Check Summary

<CodeTabs>
```csharp title="C#"
var result = await client.Job.Query.Design.SteelMember.CheckSummary.GetAsync();

foreach (var s in result.Results)
{
    Console.WriteLine($"Member {s.Member}: {s.Section} — " +
        $"{s.Failure} (factor {s.LoadFactor}, case {s.CriticalCase})");
}
```

```python title="Python"
result = await client.job.query.design.steel_member.check_summary.get()

for s in result.results:
    print(f"Member {s.member}: {s.section} — "
          f"{s.failure} (factor {s.load_factor}, case {s.critical_case})")
```

```bash title="curl"
curl http://localhost:34560/api/v1/job/query/design/steel-member/check-summary
```
</CodeTabs>

## Pagination

All query endpoints support `offset` and `limit` for pagination. By
default all results are returned. Use pagination for large result sets.

<CodeTabs>
```csharp title="C#"
// Get the first 100 node displacements
var page1 = await client.Job.Query.Analysis.Static.NodeDisplacements
    .GetAsync(config =>
    {
        config.QueryParameters.Offset = 0;
        config.QueryParameters.Limit = 100;
    });

// Get the next 100
var page2 = await client.Job.Query.Analysis.Static.NodeDisplacements
    .GetAsync(config =>
    {
        config.QueryParameters.Offset = 100;
        config.QueryParameters.Limit = 100;
    });
```

```python title="Python"
page1 = await client.job.query.analysis.static.node_displacements.get(
    offset=0, limit=100)

page2 = await client.job.query.analysis.static.node_displacements.get(
    offset=100, limit=100)
```

```bash title="curl"
# Page 1
curl "http://localhost:34560/api/v1/job/query/analysis/static/node-displacements?offset=0&limit=100"

# Page 2
curl "http://localhost:34560/api/v1/job/query/analysis/static/node-displacements?offset=100&limit=100"
```
</CodeTabs>
