AQL Query Language

Collection Operations

Master AQL’s collection operations for transforming and manipulating model data.

In this tutorial, you’ll learn how to use collect, flatten, iteration operations, and aggregation functions to transform collections and extract computed values. These operations are essential for sophisticated model analysis and data transformation.

30 mins Estimated Time

Section 1

Understanding Collection Transformation

AQL provides powerful operations for transforming collections into new forms. The collect operation extracts values from each element, flatten merges nested collections, and various aggregation operations compute summary statistics.

These operations form the core of data processing pipelines in AQL, allowing you to reshape model data for analysis, reporting, and code generation.

AQL Transformation Pipeline

Step 1

Set up a comprehensive model for collection examples.

This metamodel represents a library system with Books, Authors, Categories, and Loans. It provides rich data relationships perfect for demonstrating collection operations.

Library.ecore
1<?xml version="1.0" encoding="UTF-8"?>
2<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
5 name="Library" nsURI="http://www.example.org/library" nsPrefix="library">
6
7 <!-- Library: root container for all library entities -->
8 <eClassifiers xsi:type="ecore:EClass" name="Library">
9 <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
10 <eStructuralFeatures xsi:type="ecore:EAttribute" name="location" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
11 <eStructuralFeatures xsi:type="ecore:EReference" name="books" upperBound="-1"
12 eType="#//Book" containment="true"/>
13 <eStructuralFeatures xsi:type="ecore:EReference" name="authors" upperBound="-1"
14 eType="#//Author" containment="true"/>
15 <eStructuralFeatures xsi:type="ecore:EReference" name="categories" upperBound="-1"
16 eType="#//Category" containment="true"/>
17 <eStructuralFeatures xsi:type="ecore:EReference" name="members" upperBound="-1"
18 eType="#//Member" containment="true"/>
19 <eStructuralFeatures xsi:type="ecore:EReference" name="loans" upperBound="-1"
20 eType="#//Loan" containment="true"/>
21 </eClassifiers>
22
23 <!-- Book: individual book in the library collection -->
24 <eClassifiers xsi:type="ecore:EClass" name="Book">
25 <eStructuralFeatures xsi:type="ecore:EAttribute" name="title" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
26 <eStructuralFeatures xsi:type="ecore:EAttribute" name="isbn" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
27 <eStructuralFeatures xsi:type="ecore:EAttribute" name="pages" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
28 <eStructuralFeatures xsi:type="ecore:EAttribute" name="price" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"/>
29 <eStructuralFeatures xsi:type="ecore:EAttribute" name="publicationYear" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
30 <eStructuralFeatures xsi:type="ecore:EAttribute" name="available" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"/>
31 <eStructuralFeatures xsi:type="ecore:EAttribute" name="copies" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
32 <eStructuralFeatures xsi:type="ecore:EReference" name="authors" upperBound="-1"
33 eType="#//Author"/>
34 <eStructuralFeatures xsi:type="ecore:EReference" name="category" eType="#//Category"/>
35 </eClassifiers>
36
37 <!-- Author: writer of one or more books -->
38 <eClassifiers xsi:type="ecore:EClass" name="Author">
39 <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
40 <eStructuralFeatures xsi:type="ecore:EAttribute" name="nationality" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
41 <eStructuralFeatures xsi:type="ecore:EAttribute" name="birthYear" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
42 <eStructuralFeatures xsi:type="ecore:EReference" name="books" upperBound="-1"
43 eType="#//Book"/>
44 </eClassifiers>
45
46 <!-- Category: classification for books -->
47 <eClassifiers xsi:type="ecore:EClass" name="Category">
48 <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
49 <eStructuralFeatures xsi:type="ecore:EAttribute" name="code" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
50 <eStructuralFeatures xsi:type="ecore:EAttribute" name="description" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
51 <eStructuralFeatures xsi:type="ecore:EReference" name="subcategories" upperBound="-1"
52 eType="#//Category" containment="true"/>
53 <eStructuralFeatures xsi:type="ecore:EReference" name="parent" eType="#//Category"/>
54 </eClassifiers>
55
56 <!-- Member: library member who borrows books -->
57 <eClassifiers xsi:type="ecore:EClass" name="Member">
58 <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
59 <eStructuralFeatures xsi:type="ecore:EAttribute" name="memberId" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
60 <eStructuralFeatures xsi:type="ecore:EAttribute" name="membershipYear" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
61 <eStructuralFeatures xsi:type="ecore:EReference" name="borrowed" upperBound="-1"
62 eType="#//Book"/>
63 <eStructuralFeatures xsi:type="ecore:EReference" name="favourites" upperBound="-1"
64 eType="#//Book"/>
65 </eClassifiers>
66
67 <!-- Loan: book loan transaction -->
68 <eClassifiers xsi:type="ecore:EClass" name="Loan">
69 <eStructuralFeatures xsi:type="ecore:EAttribute" name="loanDate" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
70 <eStructuralFeatures xsi:type="ecore:EAttribute" name="dueDate" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
71 <eStructuralFeatures xsi:type="ecore:EAttribute" name="returned" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EBoolean"/>
72 <eStructuralFeatures xsi:type="ecore:EReference" name="member" eType="#//Member"/>
73 <eStructuralFeatures xsi:type="ecore:EReference" name="book" eType="#//Book"/>
74 </eClassifiers>
75</ecore:EPackage>

Step 2

Create a model instance with nested collections.

This model contains multiple books by various authors, different categories, and loan records. The nested structure demonstrates collection operations across related objects.

library-data.xmi
1<?xml version="1.0" encoding="UTF-8"?>
2<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
3 xmlns:library="http://www.example.org/library">
4
5 <library:Library name="City Central Library" location="Melbourne">
6 <!-- Categories -->
7 <categories name="Fiction" code="FIC" description="Fictional works and novels">
8 <subcategories name="Science Fiction" code="SF" description="Speculative fiction with scientific themes"/>
9 <subcategories name="Fantasy" code="FAN" description="Fantasy and magical realism"/>
10 <subcategories name="Mystery" code="MYS" description="Detective and mystery novels"/>
11 </categories>
12 <categories name="Non-Fiction" code="NF" description="Factual and educational works">
13 <subcategories name="Biography" code="BIO" description="Life stories and memoirs"/>
14 <subcategories name="Science" code="SCI" description="Scientific texts and popular science"/>
15 <subcategories name="History" code="HIS" description="Historical accounts and analysis"/>
16 </categories>
17 <categories name="Technical" code="TECH" description="Technical and professional books">
18 <subcategories name="Programming" code="PROG" description="Software development books"/>
19 <subcategories name="Engineering" code="ENG" description="Engineering texts"/>
20 </categories>
21
22 <!-- Authors -->
23 <authors name="Jane Austen" nationality="British" birthYear="1775" books="//@books.0 //@books.1"/>
24 <authors name="Isaac Asimov" nationality="American" birthYear="1920" books="//@books.2 //@books.3"/>
25 <authors name="Agatha Christie" nationality="British" birthYear="1890" books="//@books.4 //@books.5"/>
26 <authors name="Stephen Hawking" nationality="British" birthYear="1942" books="//@books.6"/>
27 <authors name="J.R.R. Tolkien" nationality="British" birthYear="1892" books="//@books.7 //@books.8"/>
28 <authors name="George Orwell" nationality="British" birthYear="1903" books="//@books.9 //@books.10"/>
29 <authors name="Robert Martin" nationality="American" birthYear="1952" books="//@books.11"/>
30 <authors name="Marie Curie" nationality="Polish" birthYear="1867" books="//@books.12"/>
31 <authors name="Ada Lovelace" nationality="British" birthYear="1815" books="//@books.13"/>
32 <authors name="Charles Darwin" nationality="British" birthYear="1809" books="//@books.14"/>
33
34 <!-- Books with varying attributes -->
35 <books title="Pride and Prejudice" isbn="978-0141439518" pages="432" price="12.99" publicationYear="1813" available="true" copies="5" authors="//@authors.0" category="//@categories.0"/>
36 <books title="Sense and Sensibility" isbn="978-0141439662" pages="409" price="11.99" publicationYear="1811" available="true" copies="3" authors="//@authors.0" category="//@categories.0"/>
37 <books title="Foundation" isbn="978-0553293357" pages="244" price="15.99" publicationYear="1951" available="true" copies="4" authors="//@authors.1" category="//@categories.0/subcategories.0"/>
38 <books title="I, Robot" isbn="978-0553382563" pages="224" price="14.99" publicationYear="1950" available="false" copies="2" authors="//@authors.1" category="//@categories.0/subcategories.0"/>
39 <books title="Murder on the Orient Express" isbn="978-0062693662" pages="256" price="13.99" publicationYear="1934" available="true" copies="6" authors="//@authors.2" category="//@categories.0/subcategories.2"/>
40 <books title="The ABC Murders" isbn="978-0062073587" pages="272" price="12.99" publicationYear="1936" available="true" copies="4" authors="//@authors.2" category="//@categories.0/subcategories.2"/>
41 <books title="A Brief History of Time" isbn="978-0553380163" pages="212" price="18.99" publicationYear="1988" available="true" copies="8" authors="//@authors.3" category="//@categories.1/subcategories.1"/>
42 <books title="The Hobbit" isbn="978-0547928227" pages="300" price="14.99" publicationYear="1937" available="true" copies="7" authors="//@authors.4" category="//@categories.0/subcategories.1"/>
43 <books title="The Lord of the Rings" isbn="978-0544003415" pages="1178" price="35.99" publicationYear="1954" available="false" copies="3" authors="//@authors.4" category="//@categories.0/subcategories.1"/>
44 <books title="1984" isbn="978-0451524935" pages="328" price="9.99" publicationYear="1949" available="true" copies="10" authors="//@authors.5" category="//@categories.0"/>
45 <books title="Animal Farm" isbn="978-0451526342" pages="112" price="8.99" publicationYear="1945" available="true" copies="6" authors="//@authors.5" category="//@categories.0"/>
46 <books title="Clean Code" isbn="978-0132350884" pages="464" price="39.99" publicationYear="2008" available="true" copies="5" authors="//@authors.6" category="//@categories.2/subcategories.0"/>
47 <books title="Radioactive Substances" isbn="978-1234567890" pages="156" price="45.00" publicationYear="1904" available="true" copies="2" authors="//@authors.7" category="//@categories.1/subcategories.1"/>
48 <books title="Notes on Programming" isbn="978-0987654321" pages="89" price="55.00" publicationYear="1843" available="true" copies="1" authors="//@authors.8" category="//@categories.2/subcategories.0"/>
49 <books title="On the Origin of Species" isbn="978-0451529060" pages="703" price="16.99" publicationYear="1859" available="true" copies="4" authors="//@authors.9" category="//@categories.1/subcategories.1"/>
50
51 <!-- Library Members -->
52 <members name="Alice Thompson" memberId="M001" membershipYear="2020" borrowed="//@books.2 //@books.6" favourites="//@books.2 //@books.3 //@books.6"/>
53 <members name="Bob Richardson" memberId="M002" membershipYear="2019" borrowed="//@books.0 //@books.9" favourites="//@books.0 //@books.1 //@books.9"/>
54 <members name="Carol Mitchell" memberId="M003" membershipYear="2021" borrowed="//@books.4" favourites="//@books.4 //@books.5"/>
55 <members name="David Patterson" memberId="M004" membershipYear="2018" borrowed="//@books.7 //@books.8 //@books.11" favourites="//@books.7 //@books.8 //@books.11"/>
56 <members name="Emma Williams" memberId="M005" membershipYear="2022" borrowed="" favourites="//@books.6 //@books.12 //@books.14"/>
57 <members name="Frank Anderson" memberId="M006" membershipYear="2017" borrowed="//@books.10 //@books.14" favourites="//@books.9 //@books.10"/>
58 </library:Library>
59</xmi:XMI>

Step 3

Explore basic collection properties.

Start with fundamental collection operations: size calculation, empty/notEmpty checks, and basic element access. These form the foundation for more complex operations.

Terminal
1# Collection Basics - Understanding AQL Collections
2# Collections are the foundation of data manipulation in AQL
3
4# Get all books in the library
5swift-aql evaluate --model library-data.xmi \
6 --expression "library.books"
7
8# Output: [Book(Pride and Prejudice), Book(Sense and Sensibility), ...]
9
10# Get the size of a collection
11swift-aql evaluate --model library-data.xmi \
12 --expression "library.books->size()"
13
14# Output: 15
15
16# Check if a collection is empty
17swift-aql evaluate --model library-data.xmi \
18 --expression "library.books->isEmpty()"
19
20# Output: false
21
22# Check if a collection is not empty
23swift-aql evaluate --model library-data.xmi \
24 --expression "library.authors->notEmpty()"
25
26# Output: true
27
28# Get the first element of a collection
29swift-aql evaluate --model library-data.xmi \
30 --expression "library.books->first()"
31
32# Output: Book(Pride and Prejudice)
33
34# Get the last element of a collection
35swift-aql evaluate --model library-data.xmi \
36 --expression "library.books->last()"
37
38# Output: Book(On the Origin of Species)

Step 4

Access nested collections through navigation.

Navigate through model relationships to access collections at different levels. Understanding navigation is crucial for effective collection processing.

Terminal
1# Collect Operation - Transforming Collections
2# The collect operation extracts or transforms values from each element
3
4# Extract all book titles
5swift-aql evaluate --model library-data.xmi \
6 --expression "library.books->collect(b | b.title)"
7
8# Output: ['Pride and Prejudice', 'Sense and Sensibility', 'Foundation', ...]
9
10# Extract page counts from all books
11swift-aql evaluate --model library-data.xmi \
12 --expression "library.books->collect(b | b.pages)"
13
14# Output: [432, 409, 244, 224, 256, 272, 212, 300, 1178, 328, 112, 464, 156, 89, 703]
15
16# Extract prices as a collection
17swift-aql evaluate --model library-data.xmi \
18 --expression "library.books->collect(b | b.price)"
19
20# Output: [12.99, 11.99, 15.99, 14.99, 13.99, 12.99, 18.99, 14.99, 35.99, 9.99, 8.99, 39.99, 45.0, 55.0, 16.99]
21
22# Shorthand syntax without explicit iterator variable
23swift-aql evaluate --model library-data.xmi \
24 --expression "library.authors.name"
25
26# Output: ['Jane Austen', 'Isaac Asimov', 'Agatha Christie', ...]
27
28# Collect computed values - calculate age of each book
29swift-aql evaluate --model library-data.xmi \
30 --expression "library.books->collect(b | 2024 - b.publicationYear)"
31
32# Output: [211, 213, 73, 74, 90, 88, 36, 87, 70, 75, 79, 16, 120, 181, 165]

Section 2

Collect Operations

The collect operation is AQL’s most powerful transformation tool. It applies an expression to each element in a collection and returns a new collection with the results.

Think of collect as a mapping operation—it transforms each element according to a rule you specify, creating a new collection with the transformed values.

Step 1

Extract simple properties with collect.

Use collect to extract property values from each element in a collection. This creates a new collection containing just the values you’re interested in.

Terminal
1# Nested Collect Operations
2# Working with collections within collections
3
4# Get all authors for each book (returns collection of collections)
5swift-aql evaluate --model library-data.xmi \
6 --expression "library.books->collect(b | b.authors)"
7
8# Output: [[Author(Jane Austen)], [Author(Jane Austen)], [Author(Isaac Asimov)], ...]
9
10# Get author names for each book
11swift-aql evaluate --model library-data.xmi \
12 --expression "library.books->collect(b | b.authors->collect(a | a.name))"
13
14# Output: [['Jane Austen'], ['Jane Austen'], ['Isaac Asimov'], ...]
15
16# Collect books from each category
17swift-aql evaluate --model library-data.xmi \
18 --expression "library.categories->collect(c | c.subcategories->collect(s | s.name))"
19
20# Output: [['Science Fiction', 'Fantasy', 'Mystery'], ['Biography', 'Science', 'History'], ['Programming', 'Engineering']]
21
22# Collect member borrowing information
23swift-aql evaluate --model library-data.xmi \
24 --expression "library.members->collect(m | m.borrowed->collect(b | b.title))"
25
26# Output: [['Foundation', 'A Brief History of Time'], ['Pride and Prejudice', '1984'], ...]
27
28# Nested collect with transformations
29swift-aql evaluate --model library-data.xmi \
30 --expression "library.categories->collect(c |
31 c.name + ': ' + c.subcategories->size().toString() + ' subcategories')"
32
33# Output: ['Fiction: 3 subcategories', 'Non-Fiction: 3 subcategories', 'Technical: 2 subcategories']

Step 2

Transform elements with expressions.

Apply complex expressions within collect operations. Combine property access with calculations, string operations, and conditional logic.

Terminal
1# Flatten Operation - Combining Nested Collections
2# Flatten reduces nested collections into a single flat collection
3
4# Get all books from all authors (without flatten - nested)
5swift-aql evaluate --model library-data.xmi \
6 --expression "library.authors->collect(a | a.books)"
7
8# Output: [[Book(Pride...), Book(Sense...)], [Book(Foundation), Book(I, Robot)], ...]
9
10# Flatten to get all books in a single collection
11swift-aql evaluate --model library-data.xmi \
12 --expression "library.authors->collect(a | a.books)->flatten()"
13
14# Output: [Book(Pride...), Book(Sense...), Book(Foundation), Book(I, Robot), ...]
15
16# Get all subcategory names flattened
17swift-aql evaluate --model library-data.xmi \
18 --expression "library.categories->collect(c | c.subcategories)->flatten()->collect(s | s.name)"
19
20# Output: ['Science Fiction', 'Fantasy', 'Mystery', 'Biography', 'Science', 'History', 'Programming', 'Engineering']
21
22# Flatten member favourites to see all favourite books
23swift-aql evaluate --model library-data.xmi \
24 --expression "library.members->collect(m | m.favourites)->flatten()->collect(b | b.title)"
25
26# Output: ['Foundation', 'I, Robot', 'A Brief History of Time', ...]
27
28# Combine flatten with unique using asSet
29swift-aql evaluate --model library-data.xmi \
30 --expression "library.members->collect(m | m.favourites)->flatten()->asSet()->size()"
31
32# Output: 11 (unique favourite books across all members)
33
34# Shorthand for collect + flatten using dot notation
35swift-aql evaluate --model library-data.xmi \
36 --expression "library.categories.subcategories.name"
37
38# Output: ['Science Fiction', 'Fantasy', 'Mystery', 'Biography', 'Science', 'History', 'Programming', 'Engineering']

Step 3

Navigate through references in collect.

Use collect to navigate through references and extract properties from related objects. This enables cross-object data extraction.

Terminal
1# Sum Operation - Adding Numeric Values
2# Sum aggregates numeric collections into a single total
3
4# Calculate total pages across all books
5swift-aql evaluate --model library-data.xmi \
6 --expression "library.books->collect(b | b.pages)->sum()"
7
8# Output: 5379
9
10# Calculate total value of library inventory
11swift-aql evaluate --model library-data.xmi \
12 --expression "library.books->collect(b | b.price)->sum()"
13
14# Output: 328.84
15
16# Calculate total copies in the library
17swift-aql evaluate --model library-data.xmi \
18 --expression "library.books->collect(b | b.copies)->sum()"
19
20# Output: 70
21
22# Calculate total inventory value (price * copies)
23swift-aql evaluate --model library-data.xmi \
24 --expression "library.books->collect(b | b.price * b.copies)->sum()"
25
26# Output: 1681.60 (approximately)
27
28# Sum pages of available books only
29swift-aql evaluate --model library-data.xmi \
30 --expression "library.books->select(b | b.available)->collect(b | b.pages)->sum()"
31
32# Output: 3957
33
34# Sum with filtered collection - total value of fiction books
35swift-aql evaluate --model library-data.xmi \
36 --expression "library.books->select(b | b.category.code = 'FIC' or b.category.parent.code = 'FIC')
37 ->collect(b | b.price)->sum()"
38
39# Output: Total price of all fiction books

Step 4

Chain collect operations.

Chain multiple collect operations to perform multi-step transformations. Each operation works on the result of the previous one.

Terminal
1# Min and Max Operations - Finding Extremes
2# Find minimum and maximum values in numeric collections
3
4# Find the shortest book (by pages)
5swift-aql evaluate --model library-data.xmi \
6 --expression "library.books->collect(b | b.pages)->min()"
7
8# Output: 89 (Notes on Programming)
9
10# Find the longest book (by pages)
11swift-aql evaluate --model library-data.xmi \
12 --expression "library.books->collect(b | b.pages)->max()"
13
14# Output: 1178 (The Lord of the Rings)
15
16# Find the cheapest book price
17swift-aql evaluate --model library-data.xmi \
18 --expression "library.books->collect(b | b.price)->min()"
19
20# Output: 8.99 (Animal Farm)
21
22# Find the most expensive book price
23swift-aql evaluate --model library-data.xmi \
24 --expression "library.books->collect(b | b.price)->max()"
25
26# Output: 55.0 (Notes on Programming)
27
28# Find the oldest book (earliest publication year)
29swift-aql evaluate --model library-data.xmi \
30 --expression "library.books->collect(b | b.publicationYear)->min()"
31
32# Output: 1811 (Sense and Sensibility)
33
34# Find the newest book (latest publication year)
35swift-aql evaluate --model library-data.xmi \
36 --expression "library.books->collect(b | b.publicationYear)->max()"
37
38# Output: 2008 (Clean Code)
39
40# Find oldest author birth year
41swift-aql evaluate --model library-data.xmi \
42 --expression "library.authors->collect(a | a.birthYear)->min()"
43
44# Output: 1775 (Jane Austen)
45
46# Find maximum number of copies for any single book
47swift-aql evaluate --model library-data.xmi \
48 --expression "library.books->collect(b | b.copies)->max()"
49
50# Output: 10 (1984)

Section 3

Flatten and Nested Collections

When working with nested collections (collections that contain other collections), you often need to flatten the structure into a single collection. The flatten operation merges nested collections into one flat collection.

This is essential when navigation produces collections of collections, and you need to work with all elements at once.

Step 1

Understand when flattening is needed.

When you collect collections, you get nested structures. Identify situations where you need to flatten these into a single collection for further processing.

Terminal
1# Counting Operations - Tallying Elements
2# Various ways to count elements in collections
3
4# Count total number of books
5swift-aql evaluate --model library-data.xmi \
6 --expression "library.books->size()"
7
8# Output: 15
9
10# Count available books
11swift-aql evaluate --model library-data.xmi \
12 --expression "library.books->select(b | b.available)->size()"
13
14# Output: 13
15
16# Count unavailable books
17swift-aql evaluate --model library-data.xmi \
18 --expression "library.books->reject(b | b.available)->size()"
19
20# Output: 2
21
22# Count books with more than 300 pages
23swift-aql evaluate --model library-data.xmi \
24 --expression "library.books->select(b | b.pages > 300)->size()"
25
26# Output: 5
27
28# Count British authors
29swift-aql evaluate --model library-data.xmi \
30 --expression "library.authors->select(a | a.nationality = 'British')->size()"
31
32# Output: 7
33
34# Count books per category using collect
35swift-aql evaluate --model library-data.xmi \
36 --expression "library.categories->collect(c |
37 c.name + ': ' + library.books->select(b | b.category = c)->size().toString())"
38
39# Output: ['Fiction: 4', 'Non-Fiction: 0', 'Technical: 0']
40
41# Count members with active borrowings
42swift-aql evaluate --model library-data.xmi \
43 --expression "library.members->select(m | m.borrowed->notEmpty())->size()"
44
45# Output: 5
46
47# Count total borrowed books (across all members)
48swift-aql evaluate --model library-data.xmi \
49 --expression "library.members->collect(m | m.borrowed)->flatten()->size()"
50
51# Output: 9

Step 2

Use flatten to merge collections.

The flatten operation takes a collection of collections and returns a single collection containing all elements from the nested collections.

Terminal
1# Average Calculations - Computing Mean Values
2# Calculate averages using sum and size
3
4# Calculate average book price
5swift-aql evaluate --model library-data.xmi \
6 --expression "let prices = library.books->collect(b | b.price)
7 in prices->sum() / prices->size()"
8
9# Output: 21.92 (approximately)
10
11# Calculate average page count
12swift-aql evaluate --model library-data.xmi \
13 --expression "let pages = library.books->collect(b | b.pages)
14 in pages->sum() / pages->size()"
15
16# Output: 358.6 (approximately)
17
18# Calculate average copies per book
19swift-aql evaluate --model library-data.xmi \
20 --expression "let copies = library.books->collect(b | b.copies)
21 in copies->sum() / copies->size()"
22
23# Output: 4.67 (approximately)
24
25# Average price of fiction books only
26swift-aql evaluate --model library-data.xmi \
27 --expression "let fictionBooks = library.books->select(b |
28 b.category.code = 'FIC' or b.category.parent.code = 'FIC'),
29 prices = fictionBooks->collect(b | b.price)
30 in prices->sum() / prices->size()"
31
32# Output: Average price of fiction books
33
34# Average publication year
35swift-aql evaluate --model library-data.xmi \
36 --expression "let years = library.books->collect(b | b.publicationYear)
37 in years->sum() / years->size()"
38
39# Output: 1912 (approximately - the mean publication year)
40
41# Average author birth year
42swift-aql evaluate --model library-data.xmi \
43 --expression "let years = library.authors->collect(a | a.birthYear)
44 in years->sum() / years->size()"
45
46# Output: 1866 (approximately)
47
48# Average books per member (favourites)
49swift-aql evaluate --model library-data.xmi \
50 --expression "let favCounts = library.members->collect(m | m.favourites->size())
51 in favCounts->sum() / favCounts->size()"
52
53# Output: 2.5 (approximately)

Step 3

Combine collect and flatten.

A common pattern is to collect related objects (creating nested collections) then flatten the result. This extracts all related elements across multiple parent objects.

Terminal
1# Grouping Basics - Organising Data by Criteria
2# Group elements by shared characteristics
3
4# Group books by availability status
5swift-aql evaluate --model library-data.xmi \
6 --expression "let available = library.books->select(b | b.available),
7 unavailable = library.books->reject(b | b.available)
8 in 'Available: ' + available->size() + ', Unavailable: ' + unavailable->size()"
9
10# Output: "Available: 13, Unavailable: 2"
11
12# Group authors by nationality
13swift-aql evaluate --model library-data.xmi \
14 --expression "let british = library.authors->select(a | a.nationality = 'British'),
15 american = library.authors->select(a | a.nationality = 'American'),
16 polish = library.authors->select(a | a.nationality = 'Polish')
17 in 'British: ' + british->size() + ', American: ' + american->size() + ', Polish: ' + polish->size()"
18
19# Output: "British: 7, American: 2, Polish: 1"
20
21# List British author names
22swift-aql evaluate --model library-data.xmi \
23 --expression "library.authors->select(a | a.nationality = 'British')->collect(a | a.name)"
24
25# Output: ['Jane Austen', 'Agatha Christie', 'Stephen Hawking', 'J.R.R. Tolkien', 'George Orwell', 'Ada Lovelace', 'Charles Darwin']
26
27# Group books by publication century
28swift-aql evaluate --model library-data.xmi \
29 --expression "let c19 = library.books->select(b | b.publicationYear < 1900),
30 c20 = library.books->select(b | b.publicationYear >= 1900 and b.publicationYear < 2000),
31 c21 = library.books->select(b | b.publicationYear >= 2000)
32 in '19th century: ' + c19->size() + ', 20th century: ' + c20->size() + ', 21st century: ' + c21->size()"
33
34# Output: "19th century: 4, 20th century: 10, 21st century: 1"
35
36# Group members by membership decade
37swift-aql evaluate --model library-data.xmi \
38 --expression "let pre2020 = library.members->select(m | m.membershipYear < 2020),
39 post2020 = library.members->select(m | m.membershipYear >= 2020)
40 in 'Before 2020: ' + pre2020->size() + ', 2020 onwards: ' + post2020->size()"
41
42# Output: "Before 2020: 2, 2020 onwards: 4"

Step 4

Work with deeply nested structures.

Handle complex model structures with multiple levels of nesting. Use multiple flatten operations or careful navigation to access deeply nested data.

Terminal
1# Advanced Grouping - Complex Data Organisation
2# More sophisticated grouping patterns with aggregation
3
4# Group books by category and count
5swift-aql evaluate --model library-data.xmi \
6 --expression "library.categories->collect(c |
7 c.name + ': ' + library.books->select(b |
8 b.category = c or b.category.parent = c)->size().toString() + ' books')"
9
10# Output: ['Fiction: 10 books', 'Non-Fiction: 3 books', 'Technical: 2 books']
11
12# Group books by price range
13swift-aql evaluate --model library-data.xmi \
14 --expression "let cheap = library.books->select(b | b.price < 15),
15 medium = library.books->select(b | b.price >= 15 and b.price < 30),
16 expensive = library.books->select(b | b.price >= 30)
17 in 'Under $15: ' + cheap->size() + ' ($' + cheap->collect(b | b.price)->sum().toString() + '), ' +
18 '$15-30: ' + medium->size() + ' ($' + medium->collect(b | b.price)->sum().toString() + '), ' +
19 'Over $30: ' + expensive->size() + ' ($' + expensive->collect(b | b.price)->sum().toString() + ')'"
20
21# Output: Price range distribution with totals
22
23# Group and aggregate - total pages per category
24swift-aql evaluate --model library-data.xmi \
25 --expression "library.categories->collect(c |
26 let categoryBooks = library.books->select(b | b.category = c or b.category.parent = c)
27 in c.name + ': ' + categoryBooks->collect(b | b.pages)->sum().toString() + ' pages')"
28
29# Output: ['Fiction: 3973 pages', 'Non-Fiction: 1071 pages', 'Technical: 553 pages']
30
31# Books per subcategory
32swift-aql evaluate --model library-data.xmi \
33 --expression "library.categories.subcategories->collect(s |
34 s.name + ': ' + library.books->select(b | b.category = s)->size().toString())"
35
36# Output: ['Science Fiction: 2', 'Fantasy: 2', 'Mystery: 2', 'Biography: 0', 'Science: 3', 'History: 0', 'Programming: 2', 'Engineering: 0']
37
38# Group authors by number of books written
39swift-aql evaluate --model library-data.xmi \
40 --expression "let oneBook = library.authors->select(a | a.books->size() = 1),
41 twoBooks = library.authors->select(a | a.books->size() = 2)
42 in 'Authors with 1 book: ' + oneBook->collect(a | a.name) +
43 ', Authors with 2 books: ' + twoBooks->collect(a | a.name)"
44
45# Output: Lists of authors grouped by book count

Section 4

Aggregation and Statistical Operations

AQL provides aggregation operations for computing summary statistics and aggregate values from collections. These operations reduce collections to single values.

Common aggregations include sum, maximum, minimum, and average calculations. These are essential for reporting and analysis queries.

Step 1

Calculate sums and totals.

Use sum() to calculate totals from numeric collections. This is useful for computing aggregate statistics across model elements.

Terminal
1# Iteration Basics - Processing Each Element
2# Fundamental iteration patterns in AQL
3
4# Process each book to create a summary string
5swift-aql evaluate --model library-data.xmi \
6 --expression "library.books->collect(b | b.title + ' (' + b.publicationYear.toString() + ')')"
7
8# Output: ['Pride and Prejudice (1813)', 'Sense and Sensibility (1811)', ...]
9
10# Create book descriptions with multiple fields
11swift-aql evaluate --model library-data.xmi \
12 --expression "library.books->collect(b |
13 b.title + ' by ' + b.authors->first().name + ', ' + b.pages.toString() + ' pages')"
14
15# Output: ['Pride and Prejudice by Jane Austen, 432 pages', ...]
16
17# Process authors with their book counts
18swift-aql evaluate --model library-data.xmi \
19 --expression "library.authors->collect(a |
20 a.name + ' (' + a.nationality + ') - ' + a.books->size().toString() + ' book(s)')"
21
22# Output: ['Jane Austen (British) - 2 book(s)', 'Isaac Asimov (American) - 2 book(s)', ...]
23
24# Generate member summaries
25swift-aql evaluate --model library-data.xmi \
26 --expression "library.members->collect(m |
27 m.name + ' (ID: ' + m.memberId + ') - ' +
28 m.borrowed->size().toString() + ' borrowed, ' +
29 m.favourites->size().toString() + ' favourites')"
30
31# Output: ['Alice Thompson (ID: M001) - 2 borrowed, 3 favourites', ...]
32
33# Process with conditional text
34swift-aql evaluate --model library-data.xmi \
35 --expression "library.books->collect(b |
36 b.title + ': ' + if b.available then 'In Stock' else 'Checked Out' endif)"
37
38# Output: ['Pride and Prejudice: In Stock', ..., 'I, Robot: Checked Out', ...]
39
40# Category hierarchy display
41swift-aql evaluate --model library-data.xmi \
42 --expression "library.categories->collect(c |
43 c.name + ' -> ' + c.subcategories->collect(s | s.name)->toString())"
44
45# Output: ['Fiction -> [Science Fiction, Fantasy, Mystery]', ...]

Step 2

Find maximum and minimum values.

Use max() and min() to find extreme values in collections. These operations work with any comparable values, including numbers, strings, and dates.

Terminal
1# Iteration Pipelines - Chaining Operations
2# Combining multiple operations in sequence
3
4# Filter then transform - available book titles
5swift-aql evaluate --model library-data.xmi \
6 --expression "library.books
7 ->select(b | b.available)
8 ->collect(b | b.title)"
9
10# Output: ['Pride and Prejudice', 'Sense and Sensibility', 'Foundation', ...]
11
12# Filter, transform, then sort by length
13swift-aql evaluate --model library-data.xmi \
14 --expression "library.books
15 ->select(b | b.pages > 200)
16 ->collect(b | b.title)
17 ->sortedBy(t | t.size())"
18
19# Output: Titles sorted by length of title string
20
21# Multi-stage pipeline - expensive fiction books
22swift-aql evaluate --model library-data.xmi \
23 --expression "library.books
24 ->select(b | b.category.code = 'FIC' or b.category.parent.code = 'FIC')
25 ->select(b | b.price > 15)
26 ->collect(b | b.title + ': $' + b.price.toString())"
27
28# Output: ['Foundation: $15.99', 'A Brief History of Time: $18.99', 'The Lord of the Rings: $35.99']
29
30# Pipeline with navigation - British authors' available books
31swift-aql evaluate --model library-data.xmi \
32 --expression "library.authors
33 ->select(a | a.nationality = 'British')
34 ->collect(a | a.books)
35 ->flatten()
36 ->select(b | b.available)
37 ->collect(b | b.title)"
38
39# Output: Available books written by British authors
40
41# Pipeline with aggregation at the end
42swift-aql evaluate --model library-data.xmi \
43 --expression "library.books
44 ->select(b | b.publicationYear >= 1900)
45 ->select(b | b.available)
46 ->collect(b | b.price)
47 ->sum()"
48
49# Output: Total price of available 20th/21st century books
50
51# Complex pipeline - member activity summary
52swift-aql evaluate --model library-data.xmi \
53 --expression "library.members
54 ->select(m | m.borrowed->notEmpty())
55 ->collect(m | m.name)
56 ->sortedBy(n | n)"
57
58# Output: Sorted list of members with active borrowings

Step 3

Count elements with specific properties.

Combine filtering with size calculation to count elements that meet specific criteria. This pattern is essential for statistical analysis.

Terminal
1# Set Operations - Union, Intersection, Difference
2# Working with sets and unique collections
3
4# Convert collection to set (remove duplicates)
5swift-aql evaluate --model library-data.xmi \
6 --expression "library.authors->collect(a | a.nationality)->asSet()"
7
8# Output: {'British', 'American', 'Polish'}
9
10# Union of two collections - all favourite and borrowed books
11swift-aql evaluate --model library-data.xmi \
12 --expression "let borrowed = library.members->collect(m | m.borrowed)->flatten(),
13 favourites = library.members->collect(m | m.favourites)->flatten()
14 in borrowed->union(favourites)->asSet()->size()"
15
16# Output: Number of unique books that are either borrowed or favourited
17
18# Intersection - books that are both borrowed AND favourited
19swift-aql evaluate --model library-data.xmi \
20 --expression "let borrowed = library.members->collect(m | m.borrowed)->flatten()->asSet(),
21 favourites = library.members->collect(m | m.favourites)->flatten()->asSet()
22 in borrowed->intersection(favourites)->collect(b | b.title)"
23
24# Output: Titles of books in both sets
25
26# Difference - favourites that are not currently borrowed
27swift-aql evaluate --model library-data.xmi \
28 --expression "let borrowed = library.members->collect(m | m.borrowed)->flatten()->asSet(),
29 favourites = library.members->collect(m | m.favourites)->flatten()->asSet()
30 in favourites->difference(borrowed)->collect(b | b.title)"
31
32# Output: Books that are favourited but not borrowed
33
34# Symmetric difference - books in one set but not both
35swift-aql evaluate --model library-data.xmi \
36 --expression "let borrowed = library.members->collect(m | m.borrowed)->flatten()->asSet(),
37 favourites = library.members->collect(m | m.favourites)->flatten()->asSet()
38 in borrowed->symmetricDifference(favourites)->size()"
39
40# Output: Count of books in exactly one of the two sets
41
42# Check if one set is subset of another
43swift-aql evaluate --model library-data.xmi \
44 --expression "let aliceFavs = library.members->select(m | m.name = 'Alice Thompson')->first().favourites->asSet(),
45 allBooks = library.books->asSet()
46 in aliceFavs->includesAll(allBooks)"
47
48# Output: false (Alice's favourites is not a superset of all books)

Step 4

Create complex aggregations.

Build sophisticated aggregation queries that combine multiple operations, filtering, and transformation to produce comprehensive statistics.

Terminal
1# Sorting Operations - Ordering Collections
2# Sort collections by various criteria
3
4# Sort books by title alphabetically
5swift-aql evaluate --model library-data.xmi \
6 --expression "library.books->sortedBy(b | b.title)->collect(b | b.title)"
7
8# Output: ['1984', 'A Brief History of Time', 'Animal Farm', 'Clean Code', ...]
9
10# Sort books by price (ascending)
11swift-aql evaluate --model library-data.xmi \
12 --expression "library.books->sortedBy(b | b.price)->collect(b | b.title + ': $' + b.price.toString())"
13
14# Output: ['Animal Farm: $8.99', '1984: $9.99', 'Sense and Sensibility: $11.99', ...]
15
16# Sort books by page count (descending) using negative value
17swift-aql evaluate --model library-data.xmi \
18 --expression "library.books->sortedBy(b | -b.pages)->collect(b | b.title + ' (' + b.pages.toString() + ' pages)')"
19
20# Output: ['The Lord of the Rings (1178 pages)', 'On the Origin of Species (703 pages)', ...]
21
22# Sort authors by birth year (oldest first)
23swift-aql evaluate --model library-data.xmi \
24 --expression "library.authors->sortedBy(a | a.birthYear)->collect(a | a.name + ' (b. ' + a.birthYear.toString() + ')')"
25
26# Output: ['Jane Austen (b. 1775)', 'Charles Darwin (b. 1809)', 'Ada Lovelace (b. 1815)', ...]
27
28# Sort books by publication year (newest first)
29swift-aql evaluate --model library-data.xmi \
30 --expression "library.books->sortedBy(b | -b.publicationYear)->collect(b | b.title + ' (' + b.publicationYear.toString() + ')')"
31
32# Output: ['Clean Code (2008)', 'A Brief History of Time (1988)', ...]
33
34# Sort members by number of borrowed books
35swift-aql evaluate --model library-data.xmi \
36 --expression "library.members->sortedBy(m | -m.borrowed->size())->collect(m |
37 m.name + ': ' + m.borrowed->size().toString() + ' books borrowed')"
38
39# Output: ['David Patterson: 3 books borrowed', 'Alice Thompson: 2 books borrowed', ...]
40
41# Sort with filtered collection first
42swift-aql evaluate --model library-data.xmi \
43 --expression "library.books
44 ->select(b | b.available)
45 ->sortedBy(b | b.price)
46 ->collect(b | b.title)"
47
48# Output: Available books sorted by price

Section 5

Iteration and Advanced Patterns

Advanced collection operations include iteration patterns, grouping operations, and complex data transformation pipelines.

These patterns combine multiple AQL operations to solve complex model analysis problems and prepare data for code generation or reporting.

Step 1

Use iteration for complex processing.

Apply iterative processing patterns when simple collect operations aren’t sufficient. Use nested operations to handle complex data relationships.

Terminal
1# Any and One Operations - Selecting Single Elements
2# Extract individual elements from collections
3
4# Get any book from the collection
5swift-aql evaluate --model library-data.xmi \
6 --expression "library.books->any(true).title"
7
8# Output: A title of any book (non-deterministic)
9
10# Get any available book
11swift-aql evaluate --model library-data.xmi \
12 --expression "library.books->any(b | b.available).title"
13
14# Output: Title of any available book
15
16# Get one specific book matching criteria
17swift-aql evaluate --model library-data.xmi \
18 --expression "library.books->one(b | b.isbn = '978-0553380163').title"
19
20# Output: 'A Brief History of Time'
21
22# Get any expensive book
23swift-aql evaluate --model library-data.xmi \
24 --expression "library.books->any(b | b.price > 40).title"
25
26# Output: Either 'Radioactive Substances' or 'Notes on Programming'
27
28# Get any British author
29swift-aql evaluate --model library-data.xmi \
30 --expression "library.authors->any(a | a.nationality = 'British').name"
31
32# Output: Name of any British author
33
34# Get the one Polish author (unique match)
35swift-aql evaluate --model library-data.xmi \
36 --expression "library.authors->one(a | a.nationality = 'Polish').name"
37
38# Output: 'Marie Curie'
39
40# Get any subcategory of Fiction
41swift-aql evaluate --model library-data.xmi \
42 --expression "library.categories->select(c | c.code = 'FIC')->first().subcategories->any(true).name"
43
44# Output: Any of 'Science Fiction', 'Fantasy', or 'Mystery'
45
46# Get any member with no current borrowings
47swift-aql evaluate --model library-data.xmi \
48 --expression "library.members->any(m | m.borrowed->isEmpty()).name"
49
50# Output: 'Emma Williams'

Step 2

Group elements by properties.

While AQL doesn’t have built-in grouping, you can achieve grouping effects by filtering collections based on common property values.

Terminal
1# Includes and Excludes Operations - Membership Testing
2# Check if collections contain specific elements
3
4# Check if a specific book is in the library
5swift-aql evaluate --model library-data.xmi \
6 --expression "library.books->collect(b | b.title)->includes('1984')"
7
8# Output: true
9
10# Check if a book title is NOT in the library
11swift-aql evaluate --model library-data.xmi \
12 --expression "library.books->collect(b | b.title)->excludes('War and Peace')"
13
14# Output: true
15
16# Check if member has borrowed a specific book
17swift-aql evaluate --model library-data.xmi \
18 --expression "let aliceBorrowed = library.members->select(m | m.name = 'Alice Thompson')->first().borrowed,
19 foundation = library.books->select(b | b.title = 'Foundation')->first()
20 in aliceBorrowed->includes(foundation)"
21
22# Output: true
23
24# Check if all specified items are in a collection
25swift-aql evaluate --model library-data.xmi \
26 --expression "library.authors->collect(a | a.nationality)->includesAll(Sequence{'British', 'American'})"
27
28# Output: true
29
30# Check if none of the specified items are in collection
31swift-aql evaluate --model library-data.xmi \
32 --expression "library.authors->collect(a | a.nationality)->excludesAll(Sequence{'French', 'German'})"
33
34# Output: true
35
36# Check if any category contains programming books
37swift-aql evaluate --model library-data.xmi \
38 --expression "library.categories.subcategories->collect(s | s.code)->includes('PROG')"
39
40# Output: true
41
42# Check member's favourites include a specific title
43swift-aql evaluate --model library-data.xmi \
44 --expression "library.members->select(m |
45 m.favourites->collect(b | b.title)->includes('Foundation'))->collect(m | m.name)"
46
47# Output: ['Alice Thompson']
48
49# Check which members have NOT borrowed any books
50swift-aql evaluate --model library-data.xmi \
51 --expression "library.members->select(m |
52 library.books->excludesAll(m.borrowed))->collect(m | m.name)"
53
54# Output: ['Emma Williams']

Step 3

Build transformation pipelines.

Chain multiple operations together to create data transformation pipelines. This approach breaks complex queries into manageable steps.

Terminal
1# Complex Pipelines - Advanced Collection Processing
2# Combining multiple operations for sophisticated queries
3
4# Find most popular category by total copies available
5swift-aql evaluate --model library-data.xmi \
6 --expression "library.categories->sortedBy(c |
7 -library.books->select(b | b.category = c or b.category.parent = c)
8 ->collect(b | b.copies)->sum())->first().name"
9
10# Output: Category with most total copies
11
12# Get British authors sorted by their average book length
13swift-aql evaluate --model library-data.xmi \
14 --expression "library.authors
15 ->select(a | a.nationality = 'British')
16 ->sortedBy(a | -a.books->collect(b | b.pages)->sum() / a.books->size())
17 ->collect(a | a.name + ': avg ' + (a.books->collect(b | b.pages)->sum() / a.books->size()).toString() + ' pages')"
18
19# Output: British authors sorted by average book page count
20
21# Pipeline with multiple aggregations - library statistics
22swift-aql evaluate --model library-data.xmi \
23 --expression "let totalBooks = library.books->size(),
24 totalCopies = library.books->collect(b | b.copies)->sum(),
25 avgPrice = library.books->collect(b | b.price)->sum() / totalBooks,
26 totalValue = library.books->collect(b | b.price * b.copies)->sum()
27 in 'Books: ' + totalBooks + ', Copies: ' + totalCopies +
28 ', Avg Price: $' + avgPrice.toString() + ', Total Value: $' + totalValue.toString()"
29
30# Output: Comprehensive library statistics
31
32# Find members who have borrowed books by multiple authors
33swift-aql evaluate --model library-data.xmi \
34 --expression "library.members->select(m |
35 m.borrowed->collect(b | b.authors)->flatten()->asSet()->size() > 1
36 )->collect(m | m.name)"
37
38# Output: Members with books from more than one author
39
40# Top 3 most expensive available books with details
41swift-aql evaluate --model library-data.xmi \
42 --expression "library.books
43 ->select(b | b.available)
44 ->sortedBy(b | -b.price)
45 ->subSequence(1, 3)
46 ->collect(b | b.title + ' by ' + b.authors->first().name + ': $' + b.price.toString())"
47
48# Output: ['Notes on Programming by Ada Lovelace: $55.0', 'Radioactive Substances by Marie Curie: $45.0', 'Clean Code by Robert Martin: $39.99']
49
50# Members and their total borrowed page count
51swift-aql evaluate --model library-data.xmi \
52 --expression "library.members
53 ->select(m | m.borrowed->notEmpty())
54 ->sortedBy(m | -m.borrowed->collect(b | b.pages)->sum())
55 ->collect(m | m.name + ': ' + m.borrowed->collect(b | b.pages)->sum().toString() + ' pages borrowed')"
56
57# Output: Members sorted by total pages currently borrowed

Step 4

Optimise collection operations.

Apply optimisation techniques to improve query performance: minimise navigation, combine operations efficiently, and avoid redundant calculations.

Terminal
1# Optimisation Techniques - Efficient Collection Operations
2# Best practices for performant AQL queries
3
4# AVOID: Repeated collection traversal
5# Inefficient - traverses books multiple times
6swift-aql evaluate --model library-data.xmi \
7 --expression "library.books->select(b | b.available)->size() + ' available, ' +
8 library.books->select(b | not b.available)->size() + ' unavailable'"
9
10# PREFER: Single traversal with let bindings
11swift-aql evaluate --model library-data.xmi \
12 --expression "let allBooks = library.books,
13 available = allBooks->select(b | b.available),
14 unavailable = allBooks->reject(b | b.available)
15 in available->size() + ' available, ' + unavailable->size() + ' unavailable'"
16
17# Output: "13 available, 2 unavailable"
18
19# AVOID: Nested iteration with full scans
20# Inefficient - O(n*m) complexity
21swift-aql evaluate --model library-data.xmi \
22 --expression "library.books->select(b | library.authors->exists(a | a.books->includes(b)))->size()"
23
24# PREFER: Direct navigation
25swift-aql evaluate --model library-data.xmi \
26 --expression "library.books->select(b | b.authors->notEmpty())->size()"
27
28# Output: 15
29
30# OPTIMISE: Use early filtering to reduce collection size
31swift-aql evaluate --model library-data.xmi \
32 --expression "library.books
33 ->select(b | b.available)
34 ->select(b | b.price < 20)
35 ->collect(b | b.title)"
36
37# Better than filtering all conditions in transform step
38
39# OPTIMISE: Reuse computed collections with let
40swift-aql evaluate --model library-data.xmi \
41 --expression "let expensiveBooks = library.books->select(b | b.price > 30)
42 in 'Expensive books: ' + expensiveBooks->size() +
43 ', Total value: $' + expensiveBooks->collect(b | b.price)->sum().toString() +
44 ', Avg pages: ' + (expensiveBooks->collect(b | b.pages)->sum() / expensiveBooks->size()).toString()"
45
46# Output: Computed once, used three times
47
48# OPTIMISE: Use asSet() to remove duplicates early
49swift-aql evaluate --model library-data.xmi \
50 --expression "library.members
51 ->collect(m | m.favourites)
52 ->flatten()
53 ->asSet()
54 ->select(b | b.available)
55 ->size()"
56
57# Output: Count of unique available favourite books
58
59# OPTIMISE: Avoid unnecessary transformations
60# Instead of: ->collect(b | b)->select(b | b.available)
61# Use: ->select(b | b.available)
62swift-aql evaluate --model library-data.xmi \
63 --expression "library.books->select(b | b.available)->collect(b | b.title)"
64
65# Output: Direct and efficient
66
67# OPTIMISE: Combine conditions in single select
68swift-aql evaluate --model library-data.xmi \
69 --expression "library.books->select(b | b.available and b.price < 15 and b.pages > 200)->collect(b | b.title)"
70
71# Better than chaining multiple select operations
72# Output: Books matching all criteria efficiently

Check Your Understanding

Question 1 of 4

What does books->collect(b | b.title) return?

Question 2 of 4

When do you need to use flatten?

Question 3 of 4

What’s the result of numbers->select(n | n > 10)->size()?

Question 4 of 4

How do you get the total of all book pages across all books?

AQL in MTL Templates

Learn how to integrate AQL queries seamlessly into MTL templates for powerful model-driven code generation.