yq Session 04: Multi-Document
YAML files can contain multiple documents separated by ---. This session covers multi-doc processing, document selection, and YAML anchors/aliases.
Pre-Session State
-
Can read, filter, and edit YAML
-
Understand
-ifor in-place edits -
Can merge documents with
*
Setup
cat > /tmp/yq-multi.yaml << 'EOF'
apiVersion: v1
kind: Namespace
metadata:
name: wazuh
---
apiVersion: v1
kind: Service
metadata:
name: wazuh-indexer
namespace: wazuh
spec:
ports:
- port: 9200
targetPort: 9200
selector:
app: wazuh-indexer
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: wazuh-indexer
namespace: wazuh
spec:
replicas: 1
selector:
matchLabels:
app: wazuh-indexer
EOF
Lesson 1: Document Selection
Concept: documentIndex or di selects which document in a multi-doc file.
Exercise 1.1: Select first document
yq 'select(di == 0)' /tmp/yq-multi.yaml
Output: Only the Namespace document.
Exercise 1.2: Select by kind
yq 'select(.kind == "Service")' /tmp/yq-multi.yaml
Output: Only the Service document.
Exercise 1.3: Count documents
yq '[.] | length' /tmp/yq-multi.yaml
Alternatively, count with a pipeline:
yq -N 'di' /tmp/yq-multi.yaml | tail -1
Lesson 2: Iterate All Documents
Concept: Without select, yq processes all documents.
Exercise 2.1: Get kind from each document
yq '.kind' /tmp/yq-multi.yaml
Output: Namespace, Service, StatefulSet — one per line.
Exercise 2.2: Get metadata from each
yq '.metadata.name' /tmp/yq-multi.yaml
Output: wazuh, wazuh-indexer, wazuh-indexer
Lesson 3: Edit Specific Documents
Concept: Combine select(di == N) with assignment.
Exercise 3.1: Update replicas in the StatefulSet only
yq 'select(di == 2).spec.replicas = 3' /tmp/yq-multi.yaml
Output: Only the StatefulSet has replicas changed. Other docs unchanged.
Exercise 3.2: Add label to all documents
yq '.metadata.labels.managed-by = "yq-drill"' /tmp/yq-multi.yaml
Output: Every document gets the label.
Lesson 4: Anchors and Aliases
Concept: YAML anchors (&name) define reusable blocks. Aliases (*name) reference them.
Exercise 4.1: Create anchored data
cat > /tmp/yq-anchor.yaml << 'EOF'
defaults: &defaults
timeout: 30
retries: 3
tls: true
services:
vault:
<<: *defaults
port: 8200
consul:
<<: *defaults
port: 8500
timeout: 60
EOF
yq '.' /tmp/yq-anchor.yaml
Output: yq expands aliases by default.
Exercise 4.2: Explode anchors
yq 'explode(.)' /tmp/yq-anchor.yaml
Output: All anchors and aliases replaced with actual values. Useful for debugging "what does this YAML actually resolve to?"
Exercise 4.3: Check a merged value
yq '.services.consul.timeout' /tmp/yq-anchor.yaml
Output: 60 — the override wins over the anchor default of 30.
yq '.services.consul.retries' /tmp/yq-anchor.yaml
Output: 3 — inherited from the anchor.
Lesson 5: Split and Join
Concept: Split multi-doc into separate files, or join files into multi-doc.
Exercise 5.1: Split by document
mkdir -p /tmp/yq-split
yq -s '"/tmp/yq-split/doc-" + $index' /tmp/yq-multi.yaml
ls /tmp/yq-split/
Creates doc-0.yml, doc-1.yml, doc-2.yml.
Exercise 5.2: Evaluate split output
yq '.' /tmp/yq-split/doc-1.yml
Output: Just the Service document.
Summary: What You Learned
| Concept | Syntax | Example |
|---|---|---|
Document index |
|
|
Select by field |
|
|
Edit one doc |
|
Change only target document |
Explode anchors |
|
Resolve all aliases |
Split |
|
|
Exercises to Complete
-
[ ] Get all Service ports across documents
-
[ ] Add a
namespace: monitoringto only the Namespace document -
[ ] Create a YAML file with anchors, explode it, compare
-
[ ] Split
yq-multi.yaml, edit one file, recombine withcat
Next Session
Session 05: Infrastructure - Real antora.yml, GitHub Actions, k8s manifests.
Session Log
| Timestamp | Notes |
|---|---|
Start |
<Record when you started> |
End |
<Record when you finished> |