This is the multi-page printable view of this section.
Click here to print.
Return to the regular view of this page.
Query Expression Language
The W&B Query Expression Language lets you programmatically analyze and visualize your ML experiments directly in the W&B UI. Transform raw experiment data into actionable insights using powerful query operations.
Important: Where Query Expressions Run
Query Expressions are NOT local code! They are typed directly into the W&B web interface, not in your Python/JavaScript files.
Getting Started
Step 1: Log Data to W&B (Local Code)
First, you need data in W&B to query. This requires the W&B Python SDK:
pip install wandb # Only installation needed - for logging data
# your_training_script.py - runs locally
import wandb
wandb.init(project="my-ml-project")
wandb.log({"loss": 0.5, "accuracy": 0.85})
wandb.finish()
Step 2: Query Your Data (W&B Web UI)
After logging runs, analyze them in the W&B web interface:
- Open your browser and go to wandb.ai
- Navigate to your project (e.g.,
wandb.ai/your-username/my-ml-project)
- Click “+ Add Panel” → Select “Query Panel”
- Type expressions in the web editor (NOT in your local code):
// This is typed into the wandb.ai interface
runs.map(r => runSummary(r).accuracy).avg()
- See results instantly as charts or tables in your browser
Complete Example: Finding Your Best Model
Here’s what you would type in the W&B Query Panel editor to analyze a hyperparameter sweep:
// Remember: This is typed into the Query Panel at wandb.ai
// NOT in your local code files!
// Step 1: Filter to successful runs from your latest sweep
const validRuns = runs
.filter(r => r.state === "finished")
.filter(r => runConfig(r).sweep_id === "sweep_2024_01")
// Step 2: Extract key metrics and configurations
const runAnalysis = validRuns.map(r => ({
name: r.name,
accuracy: runSummary(r).best_accuracy,
loss: runSummary(r).final_loss,
learning_rate: runConfig(r).learning_rate,
batch_size: runConfig(r).batch_size,
training_time: r.duration
}))
// Step 3: Find the best run
const bestRun = validRuns
.reduce((best, current) =>
runSummary(current).best_accuracy > runSummary(best).best_accuracy
? current
: best
)
// Step 4: Calculate statistics across all runs
const stats = {
avg_accuracy: validRuns.map(r => runSummary(r).best_accuracy).avg(),
std_accuracy: validRuns.map(r => runSummary(r).best_accuracy).std(),
total_compute_hours: validRuns.map(r => r.duration).sum() / 3600
}
// Step 5: Group by hyperparameter to find optimal values
const byLearningRate = validRuns
.groupby(r => runConfig(r).learning_rate)
.map(group => ({
lr: group.key,
avg_accuracy: group.values.map(r => runSummary(r).best_accuracy).avg(),
num_runs: group.values.length
}))
Core Concepts
Chainable Operations
All operations can be chained together for powerful data transformations:
runs
.filter(/* select runs */)
.map(/* transform data */)
.groupby(/* organize results */)
.sort(/* order output */)
Type Safety
The expression language is fully typed, providing autocomplete and validation as you write queries.
Functions for querying and manipulating W&B data:
Core type definitions:
Common Patterns
The following examples show Query Expressions you would type in the W&B web UI:
Compare Model Architectures
// Type this in the Query Panel at wandb.ai
// Group runs by model type and compare average performance
runs
.groupby(r => runConfig(r).model_type)
.map(g => ({
model: g.key,
avg_accuracy: g.values.map(r => runSummary(r).accuracy).avg(),
best_accuracy: g.values.map(r => runSummary(r).accuracy).max(),
training_hours: g.values.map(r => r.duration).sum() / 3600
}))
.sort((a, b) => b.avg_accuracy - a.avg_accuracy)
Track Experiment Progress
// Monitor ongoing experiments
runs
.filter(r => r.state === "running")
.map(r => ({
name: r.name,
progress: runSummary(r).epoch / runConfig(r).total_epochs,
current_loss: runSummary(r).loss,
eta_minutes: (r.duration / runSummary(r).epoch) *
(runConfig(r).total_epochs - runSummary(r).epoch) / 60
}))
Find Optimal Hyperparameters
// Identify best performing hyperparameter combinations
runs
.filter(r => runSummary(r).val_accuracy > 0.85)
.map(r => ({
accuracy: runSummary(r).val_accuracy,
lr: runConfig(r).learning_rate,
batch_size: runConfig(r).batch_size,
optimizer: runConfig(r).optimizer
}))
.sort((a, b) => b.accuracy - a.accuracy)
.slice(0, 10) // Top 10 configurations
See Also
1.1 - Artifact
W&B artifact for versioning datasets, models, and other files.
const artifact: Artifact = {
id: "artifact_abc123",
name: "model-weights",
type: artifactType,
description: "Trained model weights",
aliases: ["latest", "production"],
createdAt: new Date("2024-01-15")
};
| Property |
Type |
Description |
id |
string |
Artifact ID |
name |
string |
Artifact name |
type |
ArtifactType |
Artifact type |
description |
string |
Optional. Artifact description |
aliases |
string[] |
Optional. List of aliases |
createdAt |
Date |
Creation timestamp |
1.3 - ArtifactVersion
A specific version of a W&B artifact.
const artifactVersion: ArtifactVersion = {
id: "version_xyz789",
version: "v3",
versionIndex: 3,
aliases: ["latest", "production"],
createdAt: new Date("2024-01-15"),
metadata: {
accuracy: 0.95,
model_type: "transformer"
}
};
| Property |
Type |
Description |
id |
string |
Version ID |
version |
string |
Version string (e.g., “v3”) |
versionIndex |
number |
Version index number |
aliases |
string[] |
Optional. List of aliases |
createdAt |
Date |
Creation timestamp |
metadata |
object |
Optional. Version metadata |
1.4 - ConfigDict
Configuration dictionary for W&B runs. Stores hyperparameters, settings, and metadata.
// Typical ML configuration:
const config: ConfigDict = {
// Training hyperparameters
learning_rate: 0.001,
batch_size: 32,
epochs: 100,
optimizer: "adam",
// Model architecture
model_name: "resnet50",
num_layers: 50,
dropout_rate: 0.2,
hidden_dims: [512, 256, 128],
// Data settings
dataset: "imagenet",
augmentation: true,
train_split: 0.8,
// System settings
device: "cuda",
num_workers: 4,
seed: 42
};
Value Types
Basic Types
string: Text values like model names, optimizers, datasets
number: Numeric values including integers, floats, and scientific notation
boolean: True/false flags
null: Null values for optional settings
Complex Types
Array: Lists of any allowed type (e.g., [512, 256, 128])
Object: Nested configuration groups with string keys
Special W&B Types (automatically handled when logging)
- W&B Tables: Appear as reference objects with table metadata (columns, rows, path)
- W&B Artifacts: Appear as reference objects with version and ID information
// What you see after logging a W&B Table to config:
const config: ConfigDict = {
// ... your normal config ...
// This appears automatically when you log wandb.Table() to config:
"evaluation_results": {
"_type": "table-file",
"ncols": 5,
"nrows": 100,
"path": "media/table/eval_results_2_abc123.table.json"
}
};
// What you see after referencing an artifact in config:
const config: ConfigDict = {
// ... your normal config ...
// This appears when you use an artifact:
"model_artifact": {
"_type": "artifactVersion",
"id": "QXJ0aWZhY3Q6MTIzNDU2",
"version": "v3",
"path": "model-weights:v3"
}
};
Common Patterns
// Nested configuration groups
const config: ConfigDict = {
optimizer: {
type: "adam",
betas: [0.9, 0.999],
weight_decay: 0.0001
},
scheduler: {
type: "cosine",
warmup_steps: 1000
}
};
// Environment and metadata
const config: ConfigDict = {
experiment_name: "baseline_v2",
git_commit: "abc123def",
python_version: "3.9.7",
cuda_version: "11.8"
};
Constraints
- Keys must be strings
- Values must be JSON-serializable
- Keys starting with
_wandb are reserved
- No functions, undefined, or symbols allowed
1.5 - Entity
Represents a W&B entity (team or individual user).
const entity: Entity = {
id: "entity_abc123",
name: "my-team",
isTeam: true
};
| Property |
Type |
Description |
id |
string |
Entity ID |
name |
string |
Entity name |
isTeam |
boolean |
Whether this is a team or individual user |
1.6 - Project
W&B project containing runs, artifacts, and reports.
const project: Project = {
name: "my-awesome-project",
entity: entity,
createdAt: new Date("2023-01-01"),
updatedAt: new Date("2024-01-20")
};
| Property |
Type |
Description |
name |
string |
Project name |
entity |
Entity |
Owning entity |
createdAt |
Date |
Creation timestamp |
updatedAt |
Date |
Last update timestamp |
1.7 - Run
A training or evaluation run logged to W&B.
const run: Run = {
id: "run_abc123",
name: "sunny-dawn-42",
state: "finished",
config: {
learning_rate: 0.001,
batch_size: 32,
epochs: 10
},
summaryMetrics: {
loss: 0.023,
accuracy: 0.95,
val_accuracy: 0.93
},
createdAt: new Date("2024-01-15T10:30:00Z"),
updatedAt: new Date("2024-01-15T14:45:00Z")
};
| Property |
Type |
Description |
id |
string |
Run ID |
name |
string |
Run name |
state |
string |
Run state (e.g., “running”, “finished”, “failed”) |
config |
ConfigDict |
Optional. Run configuration |
summaryMetrics |
SummaryDict |
Optional. Summary metrics |
createdAt |
Date |
Creation timestamp |
updatedAt |
Date |
Last update timestamp |
1.8 - SummaryDict
Summary dictionary for W&B runs. Stores final metrics, best values, and aggregated results.
// Typical training summary:
const summary: SummaryDict = {
// Final metrics
final_loss: 0.0234,
final_accuracy: 0.9523,
// Best values during training
best_val_loss: 0.0198,
best_val_accuracy: 0.9612,
best_epoch: 87,
// Training statistics
total_train_time: 3600.5, // seconds
total_steps: 50000,
early_stopped: false,
// Test set results
test_accuracy: 0.9487,
test_f1_score: 0.9465
};
Value Types
Basic Types
string: Text summaries, model paths, status messages
number: Metrics, scores, counts, durations
boolean: Binary flags like convergence status
null: For optional metrics that weren’t computed
Complex Types
Array: Lists like per-class scores (e.g., [0.92, 0.94, 0.96])
Object: Grouped metrics with string keys
Special W&B Types (automatically handled when logging)
- W&B Histograms: Appear as objects with bins and values arrays
- W&B Tables: Appear as reference objects with table metadata (columns, rows, path)
- W&B Artifacts: Appear as reference objects with version and ID information
// What you see after logging W&B special types to summary:
const summary: SummaryDict = {
// ... your normal metrics ...
// This appears when you log wandb.Histogram():
"weight_distribution": {
"_type": "histogram",
"bins": [0, 0.1, 0.2, 0.3, 0.4, 0.5],
"values": [10, 25, 45, 30, 15, 5]
},
// This appears when you log wandb.Table():
"predictions_table": {
"_type": "table-file",
"ncols": 4,
"nrows": 1000,
"path": "media/table/predictions_3_def456.table.json"
},
// This appears when you reference an artifact:
"best_model": {
"_type": "artifactVersion",
"id": "QXJ0aWZhY3Q6OTg3NjU0",
"version": "v12",
"path": "model-checkpoint:v12"
}
};
Common Patterns
// Grouped metrics by dataset split
const summary: SummaryDict = {
train: {
loss: 0.023,
accuracy: 0.975,
samples_seen: 50000
},
validation: {
loss: 0.045,
accuracy: 0.948,
samples_seen: 10000
},
test: {
loss: 0.041,
accuracy: 0.951,
samples_seen: 10000
}
};
// Multi-class classification results
const summary: SummaryDict = {
accuracy: 0.92,
macro_f1: 0.91,
per_class_precision: [0.95, 0.89, 0.92, 0.90],
per_class_recall: [0.93, 0.91, 0.90, 0.92],
confusion_matrix_logged: true // Actual matrix logged as W&B Table
};
// Model information
const summary: SummaryDict = {
total_parameters: 125_000_000,
trainable_parameters: 124_500_000,
model_size_mb: 476.8,
inference_time_ms: 23.4
};
Constraints
- Keys must be strings
- Values must be JSON-serializable
- Keys starting with
_wandb are reserved
- Special: Supports NaN for missing/invalid metrics
- No functions, undefined, or symbols allowed
1.9 - Table
W&B Table for structured data logging and visualization.
const table: Table = {
columns: ["epoch", "loss", "accuracy"],
data: [
[1, 0.5, 0.75],
[2, 0.3, 0.85],
[3, 0.2, 0.90]
]
};
| Property |
Type |
Description |
columns |
string[] |
Column names |
data |
any[][] |
Table data rows |
2.1 - Artifact Operations
Operations for querying and manipulating W&B artifacts
artifactLink
artifactLink(artifact): string
Gets the URL/link for accessing an artifact in the W&B UI.
Returns a direct link to view the artifact in the W&B web interface,
useful for generating reports or sharing artifact references.
Parameters
| Name |
Type |
Description |
artifact |
Artifact |
The artifact to get the link for |
Example: Generate Artifact Link
const link = artifactLink(myArtifact);
console.log(View artifact: ${link});
// Output: https://wandb.ai/entity/project/artifacts/type/name
Example: Create Markdown Links
const artifacts = project.artifacts();
const markdown = artifacts.map(a =>
- ${artifactName(a)}})
).join('\n');
See Also
artifactName
artifactName(artifact): string
Gets the name of an artifact.
Returns the artifact’s unique name within its project.
Parameters
| Name |
Type |
Description |
artifact |
Artifact |
The artifact to get the name from |
Example: Display Artifact Names
artifacts.forEach(artifact => {
console.log(Artifact: ${artifactName(artifact)});
});
Example: Filter by Name Pattern
const modelArtifacts = artifacts.filter(a =>
artifactName(a).includes("model")
);
See Also
artifactVersionAlias
artifactVersionAlias(version): string
Gets the alias of an artifact version.
Returns the version alias (e.g., “latest”, “best”, “production”).
Parameters
Example: Find Production Version
const prodVersion = versions.find(v =>
artifactVersionAlias(v) === "production"
);
See Also
artifactVersions - Get all versions
artifactVersionCreatedAt
artifactVersionCreatedAt(version): Date
Gets the creation date of an artifact version.
Returns when a specific version of the artifact was created.
Parameters
| Name |
Type |
Description |
version |
ArtifactVersion |
The artifact version to get creation date from |
Example: Sort Versions by Date
const sorted = versions.sort((a, b) =>
artifactVersionCreatedAt(a).getTime() -
artifactVersionCreatedAt(b).getTime()
);
See Also
artifactVersions - Get all versions
artifactVersionDigest
artifactVersionDigest(version): string
Gets the content digest/hash of an artifact version.
Returns the SHA256 digest used to verify artifact integrity.
Parameters
Example: Verify Artifact Integrity
const digest = artifactVersionDigest(version);
const expected = "sha256:abc123...";
if (digest !== expected) {
console.error("Artifact integrity check failed!");
}
See Also
artifactVersions - Get all versions
artifactVersionNumber
artifactVersionNumber(version): number
Gets the version number of an artifact version.
Returns the numeric version identifier.
Parameters
Example: Get Latest Version Number
const versions = artifactVersions(artifact);
const maxVersion = Math.max(...versions.map(v =>
artifactVersionNumber(v)
));
console.log(Latest version: v${maxVersion});
See Also
artifactVersions - Get all versions
artifactVersionSize
artifactVersionSize(version): number
Gets the size of an artifact version in bytes.
Returns the storage size of a specific artifact version.
Parameters
| Name |
Type |
Description |
version |
ArtifactVersion |
The artifact version to get size from |
Example: Display Human-Readable Size
const bytes = artifactVersionSize(version);
const mb = (bytes / 1e6).toFixed(2);
console.log(Size: ${mb} MB);
Example: Find Large Artifacts
const largeVersions = versions.filter(v =>
artifactVersionSize(v) > 1e9 // > 1GB
);
See Also
artifactVersions - Get all versions
artifactVersions
artifactVersions(artifact): ArtifactVersion[]
Gets all versions of an artifact.
Returns an array of all version objects for the artifact,
including version numbers, aliases, sizes, and timestamps.
Parameters
| Name |
Type |
Description |
artifact |
Artifact |
The artifact to get versions from |
Example: List All Versions
const versions = artifactVersions(myArtifact);
versions.forEach(v => {
console.log(v${v.version}: ${v.alias} (${v.size} bytes));
});
Example: Find Latest Version
const versions = artifactVersions(artifact);
const latest = versions.find(v => v.alias === "latest");
if (latest) {
console.log(Latest is v${latest.version});
}
Example: Calculate Total Storage
const versions = artifactVersions(artifact);
const totalSize = versions.reduce((sum, v) => sum + v.size, 0);
console.log(Total storage: ${(totalSize / 1e9).toFixed(2)} GB);
See Also
2.2 - Run Operations
Operations for querying and manipulating W&B runs
runConfig
runConfig(run): ConfigDict
Extracts the configuration dictionary (ConfigDict) from a W&B run.
The configuration contains hyperparameters and settings used when the run was initialized.
This is particularly useful for comparing configurations across experiments or filtering
runs based on specific parameter values.
Parameters
| Name |
Type |
Description |
run |
Run |
The W&B run object to extract configuration from |
Example: Basic Configuration Access
const config = runConfig(myRun);
console.log(config.learning_rate); // 0.001
console.log(config.batch_size); // 32
Example: Filtering Runs by Configuration
// Find all runs with learning rate > 0.01
const highLRRuns = runs.filter(run => {
const config = runConfig(run);
return config.learning_rate > 0.01;
});
Example: Comparing Configurations
const config1 = runConfig(baseline);
const config2 = runConfig(experiment);
const differences = Object.keys(config1).filter(key =>
config1[key] !== config2[key]
);
See Also
- runSummary - For accessing summary metrics
- runHistory - For accessing time-series data
runCreatedAt
Gets the creation timestamp of a W&B run.
Returns when the run was first initialized. Useful for chronological sorting,
filtering by date ranges, or analyzing experiment progression over time.
Parameters
| Name |
Type |
Description |
run |
Run |
The W&B run to get creation time from |
Example: Filter Recent Runs
const oneWeekAgo = new Date();
oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);
const recentRuns = runs.filter(run =>
runCreatedAt(run) > oneWeekAgo
);
Example: Sort Chronologically
const sortedRuns = runs.sort((a, b) =>
runCreatedAt(a).getTime() - runCreatedAt(b).getTime()
);
Example: Group by Date
const runsByDate = runs.reduce((groups, run) => {
const date = runCreatedAt(run).toDateString();
groups[date] = groups[date] || [];
groups[date].push(run);
return groups;
}, {});
See Also
runHeartbeatAt
runHeartbeatAt(run): Date
Gets the last heartbeat timestamp of a W&B run.
The heartbeat indicates when the run last sent data to W&B. For active runs,
this is continuously updated. For finished runs, it shows the completion time.
Parameters
| Name |
Type |
Description |
run |
Run |
The W&B run to get heartbeat from |
Example: Check if Run is Active
const isActive = (run: Run) => {
const lastHeartbeat = runHeartbeatAt(run);
const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);
return lastHeartbeat > fiveMinutesAgo;
};
See Also
runJobType
runJobType(run): string | undefined
Gets the job type of a run.
Returns the job type classification (e.g., “train”, “eval”, “sweep”) if set.
Parameters
| Name |
Type |
Description |
run |
Run |
The W&B run to get job type from |
Example: Filter by Job Type
const trainingRuns = runs.filter(run =>
runJobType(run) === "train"
);
const evalRuns = runs.filter(run =>
runJobType(run) === "eval"
);
See Also
Run - Run type definition
runLoggedArtifactVersion
runLoggedArtifactVersion(run, artifactVersionName): ArtifactVersion | undefined
Gets a specific artifact version logged (output) by a run.
Artifacts in W&B are versioned files or directories that track model checkpoints,
datasets, or other outputs. This function retrieves a specific artifact version
that was created/logged during the run’s execution.
Parameters
| Name |
Type |
Description |
run |
Run |
The W&B run that logged the artifact |
artifactVersionName |
string |
Artifact identifier as “name:alias” (e.g., “model:latest”, “dataset:v2”) |
Example: Get Latest Model
const model = runLoggedArtifactVersion(run, "model:latest");
if (model) {
console.log(Model version: v${model.version});
console.log(Model size: ${model.size} bytes);
console.log(Created: ${model.createdAt});
}
Example: Verify Output Artifacts
const requiredOutputs = ["model:latest", "evaluation:latest"];
const missing = requiredOutputs.filter(name =>
!runLoggedArtifactVersion(run, name)
);
if (missing.length > 0) {
console.warn(Missing outputs: ${missing.join(", ")});
}
See Also
runLoggedArtifactVersions
runLoggedArtifactVersions(run): ArtifactVersion[]
Gets all artifact versions logged (output) by a run.
Returns a complete list of all artifacts created during the run’s execution,
including models, datasets, checkpoints, and other outputs.
Parameters
| Name |
Type |
Description |
run |
Run |
The W&B run to get logged artifacts from |
Example: List All Outputs
const outputs = runLoggedArtifactVersions(run);
outputs.forEach(artifact => {
console.log(Logged: ${artifact.name}:${artifact.alias});
console.log( Version: ${artifact.version});
console.log( Size: ${artifact.size} bytes);
});
Example: Count Output Types
const outputs = runLoggedArtifactVersions(run);
const modelCount = outputs.filter(a => a.name.includes("model")).length;
const dataCount = outputs.filter(a => a.name.includes("data")).length;
console.log(Models: ${modelCount}, Datasets: ${dataCount});
See Also
runName
Gets the name/ID of a run.
Returns the unique run name (ID) assigned by W&B or set by the user.
Parameters
| Name |
Type |
Description |
run |
Run |
The W&B run to get name from |
Example: Display Run Names
runs.forEach(run => {
console.log(Run: ${runName(run)});
});
See Also
Run - Run type definition
runRuntime
Calculates the runtime duration of a W&B run in seconds.
Returns the total execution time from creation to last heartbeat.
For active runs, this represents the current runtime.
Parameters
| Name |
Type |
Description |
run |
Run |
The W&B run to calculate runtime for |
Example: Display Runtime
const runtime = runRuntime(myRun);
const hours = Math.floor(runtime / 3600);
const minutes = Math.floor((runtime % 3600) / 60);
console.log(Runtime: ${hours}h ${minutes}m);
Example: Filter Long-Running Experiments
const longRuns = runs.filter(run =>
runRuntime(run) > 3600 // More than 1 hour
);
See Also
runSummary
runSummary(run): SummaryDict
Retrieves summary metrics (SummaryDict) from a W&B run.
Summary metrics represent the final or best values logged during a run’s execution,
such as final accuracy, best validation loss, or total training time. These are
scalar values that summarize the run’s overall performance.
Parameters
| Name |
Type |
Description |
run |
Run |
The W&B run to extract summary from |
Example: Accessing Final Metrics
const summary = runSummary(myRun);
console.log(Final accuracy: ${summary.accuracy});
console.log(Best validation loss: ${summary.best_val_loss});
console.log(Training time: ${summary.training_time_seconds});
const bestRun = runs.reduce((best, current) => {
const bestSummary = runSummary(best);
const currentSummary = runSummary(current);
return currentSummary.accuracy > bestSummary.accuracy ? current : best;
});
const goodRuns = runs.filter(run => {
const summary = runSummary(run);
return summary.accuracy > 0.95 && summary.val_loss < 0.1;
});
See Also
- runConfig - For configuration parameters
- runHistory - For time-series metrics
runUsedArtifactVersions
runUsedArtifactVersions(run): ArtifactVersion[]
Gets all artifact versions used (input) by a run.
Returns artifacts that were consumed as inputs during the run’s execution,
such as training datasets, pretrained models, or configuration files.
Parameters
| Name |
Type |
Description |
run |
Run |
The W&B run to get used artifacts from |
const inputs = runUsedArtifactVersions(run);
console.log("Run dependencies:");
inputs.forEach(artifact => {
console.log(- ${artifact.name}:${artifact.version});
});
Example: Verify Dataset Version
const inputs = runUsedArtifactVersions(run);
const dataset = inputs.find(a => a.name === "training-data");
if (dataset && dataset.version !== 3) {
console.warn(Using outdated dataset v${dataset.version});
}
See Also
runUser
Gets the user who created the run.
Returns the W&B user object associated with the run, useful for filtering
by user or analyzing team member contributions.
Parameters
| Name |
Type |
Description |
run |
Run |
The W&B run to get user from |
Example: Filter by User
const myRuns = runs.filter(run =>
runUser(run).username === "john_doe"
);
Example: Group Runs by User
const runsByUser = runs.reduce((groups, run) => {
const user = runUser(run).username;
groups[user] = groups[user] || [];
groups[user].push(run);
return groups;
}, {});
See Also
User - User type definition