AQL Query Language

Filtering and Selection

Master AQL’s powerful filtering and selection operations to extract specific elements from collections.

In this tutorial, you’ll learn how to use select, reject, exists, and forAll operations to filter collections based on conditions. These operations are essential for writing precise queries that find exactly the model elements you need.

25 mins Estimated Time

Section 1

Understanding Collection Filtering

AQL provides several operations for working with collections of model elements. Filtering operations allow you to select subsets of collections based on boolean conditions.

The most important filtering operations are select (keep elements that match), reject (remove elements that match), exists (test if any element matches), and forAll (test if all elements match).

AQL Collection Operations

Step 1

Set up a richer model for filtering examples.

This extended metamodel includes Students with grades, Courses with credit hours, and Professors with specializations. We’ll use this to demonstrate sophisticated filtering operations.

University.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:ecore="http://www.eclipse.org/emf/2002/Ecore"
4 name="University" nsURI="http://www.example.org/university" nsPrefix="university">
5
6 <!-- University: root container for all academic entities -->
7 <eClassifiers xsi:type="ecore:EClass" name="University">
8 <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
9 <eStructuralFeatures xsi:type="ecore:EReference" name="departments" upperBound="-1"
10 eType="#//Department" containment="true"/>
11 <eStructuralFeatures xsi:type="ecore:EReference" name="students" upperBound="-1"
12 eType="#//Student" containment="true"/>
13 <eStructuralFeatures xsi:type="ecore:EReference" name="courses" upperBound="-1"
14 eType="#//Course" containment="true"/>
15 </eClassifiers>
16
17 <!-- Department: academic unit with professors -->
18 <eClassifiers xsi:type="ecore:EClass" name="Department">
19 <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
20 <eStructuralFeatures xsi:type="ecore:EAttribute" name="code" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
21 <eStructuralFeatures xsi:type="ecore:EReference" name="professors" upperBound="-1"
22 eType="#//Professor" containment="true"/>
23 <eStructuralFeatures xsi:type="ecore:EReference" name="offeredCourses" upperBound="-1"
24 eType="#//Course"/>
25 </eClassifiers>
26
27 <!-- Professor: academic staff member -->
28 <eClassifiers xsi:type="ecore:EClass" name="Professor">
29 <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
30 <eStructuralFeatures xsi:type="ecore:EAttribute" name="specialisation" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
31 <eStructuralFeatures xsi:type="ecore:EAttribute" name="yearsExperience" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
32 <eStructuralFeatures xsi:type="ecore:EReference" name="teaches" upperBound="-1"
33 eType="#//Course"/>
34 </eClassifiers>
35
36 <!-- Student: enrolled academic participant -->
37 <eClassifiers xsi:type="ecore:EClass" name="Student">
38 <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
39 <eStructuralFeatures xsi:type="ecore:EAttribute" name="studentId" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
40 <eStructuralFeatures xsi:type="ecore:EAttribute" name="grade" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EDouble"/>
41 <eStructuralFeatures xsi:type="ecore:EAttribute" name="year" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
42 <eStructuralFeatures xsi:type="ecore:EReference" name="enrolledIn" upperBound="-1"
43 eType="#//Course"/>
44 <eStructuralFeatures xsi:type="ecore:EReference" name="major" eType="#//Department"/>
45 </eClassifiers>
46
47 <!-- Course: academic subject offering -->
48 <eClassifiers xsi:type="ecore:EClass" name="Course">
49 <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
50 <eStructuralFeatures xsi:type="ecore:EAttribute" name="code" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString"/>
51 <eStructuralFeatures xsi:type="ecore:EAttribute" name="credits" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
52 <eStructuralFeatures xsi:type="ecore:EAttribute" name="level" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EInt"/>
53 <eStructuralFeatures xsi:type="ecore:EReference" name="prerequisites" upperBound="-1"
54 eType="#//Course"/>
55 </eClassifiers>
56</ecore:EPackage>

Step 2

Create a model instance with diverse data.

This model contains students with different grades, courses with varying credit hours, and professors with different specializations. Perfect for demonstrating filtering operations.

university-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:university="http://www.example.org/university">
4
5 <university:University name="Swift University">
6 <!-- Computer Science Department -->
7 <departments name="Computer Science" code="CS">
8 <professors name="Dr Alice Chen" specialisation="Algorithms" yearsExperience="15" teaches="//@courses.0 //@courses.1"/>
9 <professors name="Dr Bob Wilson" specialisation="Machine Learning" yearsExperience="8" teaches="//@courses.2 //@courses.3"/>
10 <professors name="Dr Carol Martinez" specialisation="Systems" yearsExperience="12" teaches="//@courses.4"/>
11 </departments>
12
13 <!-- Mathematics Department -->
14 <departments name="Mathematics" code="MATH">
15 <professors name="Dr David Lee" specialisation="Pure Mathematics" yearsExperience="20" teaches="//@courses.5 //@courses.6"/>
16 <professors name="Dr Emma Brown" specialisation="Applied Mathematics" yearsExperience="6" teaches="//@courses.7"/>
17 </departments>
18
19 <!-- Physics Department -->
20 <departments name="Physics" code="PHYS">
21 <professors name="Dr Frank Taylor" specialisation="Quantum Physics" yearsExperience="18" teaches="//@courses.8"/>
22 <professors name="Dr Grace Kim" specialisation="Astrophysics" yearsExperience="10" teaches="//@courses.9"/>
23 </departments>
24
25 <!-- Students with varying grades and years -->
26 <students name="Alex Johnson" studentId="S001" grade="92.5" year="3" enrolledIn="//@courses.0 //@courses.2" major="//@departments.0"/>
27 <students name="Beth Smith" studentId="S002" grade="78.0" year="2" enrolledIn="//@courses.1 //@courses.5" major="//@departments.0"/>
28 <students name="Chris Davis" studentId="S003" grade="88.5" year="4" enrolledIn="//@courses.3 //@courses.4" major="//@departments.0"/>
29 <students name="Diana Ross" studentId="S004" grade="95.0" year="1" enrolledIn="//@courses.5 //@courses.7" major="//@departments.1"/>
30 <students name="Edward White" studentId="S005" grade="65.0" year="2" enrolledIn="//@courses.0 //@courses.8" major="//@departments.2"/>
31 <students name="Fiona Green" studentId="S006" grade="82.0" year="3" enrolledIn="//@courses.2 //@courses.9" major="//@departments.0"/>
32 <students name="George Black" studentId="S007" grade="71.5" year="1" enrolledIn="//@courses.1 //@courses.6" major="//@departments.1"/>
33 <students name="Hannah Moore" studentId="S008" grade="89.0" year="4" enrolledIn="//@courses.4 //@courses.8" major="//@departments.2"/>
34 <students name="Ian Clark" studentId="S009" grade="58.0" year="2" enrolledIn="//@courses.0" major="//@departments.0"/>
35 <students name="Julia Adams" studentId="S010" grade="96.5" year="3" enrolledIn="//@courses.3 //@courses.5 //@courses.9" major="//@departments.0"/>
36
37 <!-- Courses with varying credits and levels -->
38 <courses name="Data Structures" code="CS101" credits="4" level="100"/>
39 <courses name="Algorithms" code="CS201" credits="4" level="200" prerequisites="//@courses.0"/>
40 <courses name="Machine Learning" code="CS301" credits="3" level="300" prerequisites="//@courses.1"/>
41 <courses name="Deep Learning" code="CS401" credits="3" level="400" prerequisites="//@courses.2"/>
42 <courses name="Operating Systems" code="CS302" credits="4" level="300" prerequisites="//@courses.0"/>
43 <courses name="Calculus I" code="MATH101" credits="4" level="100"/>
44 <courses name="Linear Algebra" code="MATH201" credits="3" level="200" prerequisites="//@courses.5"/>
45 <courses name="Differential Equations" code="MATH301" credits="3" level="300" prerequisites="//@courses.5 //@courses.6"/>
46 <courses name="Quantum Mechanics" code="PHYS301" credits="4" level="300" prerequisites="//@courses.5"/>
47 <courses name="Astrophysics" code="PHYS401" credits="3" level="400" prerequisites="//@courses.8"/>
48 </university:University>
49</xmi:XMI>

Step 3

Test basic collection access.

Before filtering, understand how to access collections. Use navigation to get collections of related objects, then apply filtering operations.

Terminal
1# Access collections through navigation
2# Get all students from the university
3swift-aql evaluate --model university-data.xmi \
4 --expression "university.students"
5
6# Output: [Student(Alex), Student(Beth), Student(Chris), ...]
7
8# Access nested collections - all professors in all departments
9swift-aql evaluate --model university-data.xmi \
10 --expression "university.departments.professors"
11
12# Output: [Professor(Dr Alice Chen), Professor(Dr Bob Wilson), ...]

Step 4

Explore collection sizes and basic properties.

Use size() to count elements, isEmpty() to check for empty collections, and notEmpty() to check for non-empty collections. These are often used in conditions.

Terminal
1# Collection size and emptiness checks
2# Count all students
3swift-aql evaluate --model university-data.xmi \
4 --expression "university.students->size()"
5
6# Output: 10
7
8# Check if there are any students
9swift-aql evaluate --model university-data.xmi \
10 --expression "university.students->notEmpty()"
11
12# Output: true
13
14# Check for empty prerequisites on introductory courses
15swift-aql evaluate --model university-data.xmi \
16 --expression "university.courses->select(c | c.prerequisites->isEmpty())->size()"
17
18# Output: 3 (CS101, MATH101, and one other have no prerequisites)

Section 2

Select and Reject Operations

The select operation filters collections to keep only elements that satisfy a condition. The reject operation does the opposite—it filters out elements that satisfy a condition.

Both operations use lambda expressions with a variable that represents each element being tested. The condition must evaluate to a boolean value.

Step 1

Select elements with simple conditions.

The select operation keeps elements where the condition is true. Use comparison operators to test properties against literal values.

Terminal
1# Simple select with comparison
2# Select students with grade >= 85
3swift-aql evaluate --model university-data.xmi \
4 --expression "university.students->select(s | s.grade >= 85)"
5
6# Output: [Student(Alex, 92.5), Student(Chris, 88.5), Student(Diana, 95.0),
7# Student(Hannah, 89.0), Student(Julia, 96.5)]
8
9# Select courses with 4 credits
10swift-aql evaluate --model university-data.xmi \
11 --expression "university.courses->select(c | c.credits = 4)"
12
13# Output: [Course(Data Structures), Course(Algorithms),
14# Course(Operating Systems), Course(Calculus I), Course(Quantum Mechanics)]

Step 2

Use reject to exclude elements.

The reject operation removes elements where the condition is true. This is the logical opposite of select and often reads more naturally for negative conditions.

Terminal
1# Reject operation - opposite of select
2# Reject students with passing grades (keep failing students)
3swift-aql evaluate --model university-data.xmi \
4 --expression "university.students->reject(s | s.grade >= 60)"
5
6# Output: [Student(Ian, 58.0)]
7
8# Reject introductory courses (keep advanced courses)
9swift-aql evaluate --model university-data.xmi \
10 --expression "university.courses->reject(c | c.level = 100)"
11
12# Output: [Course(Algorithms, 200), Course(Machine Learning, 300),
13# Course(Deep Learning, 400), Course(Operating Systems, 300), ...]

Step 3

Combine multiple conditions.

Use and and or operators to combine conditions. Parentheses can group conditions for complex logic. This allows precise filtering with multiple criteria.

Terminal
1# Combining conditions with and/or
2# Select students with high grades AND in year 3 or above
3swift-aql evaluate --model university-data.xmi \
4 --expression "university.students->select(s | s.grade >= 85 and s.year >= 3)"
5
6# Output: [Student(Alex, 92.5, year 3), Student(Chris, 88.5, year 4),
7# Student(Hannah, 89.0, year 4), Student(Julia, 96.5, year 3)]
8
9# Select courses that are either 4 credits OR level 400
10swift-aql evaluate --model university-data.xmi \
11 --expression "university.courses->select(c | c.credits = 4 or c.level = 400)"
12
13# Output: [Course(Data Structures, 4 credits), Course(Algorithms, 4 credits),
14# Course(Deep Learning, level 400), Course(Astrophysics, level 400), ...]
15
16# Complex condition with parentheses
17swift-aql evaluate --model university-data.xmi \
18 --expression "university.students->select(s | (s.grade >= 80 and s.year <= 2) or s.grade >= 95)"
19
20# Output: Students matching either condition

Step 4

Filter based on related object properties.

Filter elements based on properties of related objects. Navigate through references within the filter condition to access nested properties.

Terminal
1# Filter based on related object properties
2# Select students majoring in Computer Science
3swift-aql evaluate --model university-data.xmi \
4 --expression "university.students->select(s | s.major.name = 'Computer Science')"
5
6# Output: [Student(Alex), Student(Beth), Student(Chris),
7# Student(Fiona), Student(Ian), Student(Julia)]
8
9# Select professors with more than 10 years experience
10# who teach courses at level 300 or above
11swift-aql evaluate --model university-data.xmi \
12 --expression "university.departments.professors->select(p |
13 p.yearsExperience > 10 and p.teaches->exists(c | c.level >= 300))"
14
15# Output: [Professor(Dr Alice Chen), Professor(Dr Carol Martinez),
16# Professor(Dr David Lee), Professor(Dr Frank Taylor)]

Section 3

Existence and Universal Quantifiers

The exists operation tests whether any element in a collection satisfies a condition. The forAll operation tests whether all elements satisfy a condition.

These quantifier operations return boolean values and are often used in conditional logic or as part of larger filtering expressions.

Step 1

Test for existence with exists.

Use exists to check if any element meets a condition. This is useful for conditional logic and validation queries.

Terminal
1# Testing existence with exists
2# Check if any student has a perfect score (100)
3swift-aql evaluate --model university-data.xmi \
4 --expression "university.students->exists(s | s.grade = 100)"
5
6# Output: false
7
8# Check if there are any failing students
9swift-aql evaluate --model university-data.xmi \
10 --expression "university.students->exists(s | s.grade < 60)"
11
12# Output: true (Ian has 58.0)
13
14# Check if any department has professors with 20+ years experience
15swift-aql evaluate --model university-data.xmi \
16 --expression "university.departments->exists(d |
17 d.professors->exists(p | p.yearsExperience >= 20))"
18
19# Output: true (Dr David Lee has 20 years)

Step 2

Verify conditions with forAll.

Use forAll to verify that all elements meet a condition. This is essential for validation and constraint checking.

Terminal
1# Universal quantification with forAll
2# Check if all students have passing grades
3swift-aql evaluate --model university-data.xmi \
4 --expression "university.students->forAll(s | s.grade >= 60)"
5
6# Output: false (Ian has 58.0)
7
8# Check if all courses have at least 3 credits
9swift-aql evaluate --model university-data.xmi \
10 --expression "university.courses->forAll(c | c.credits >= 3)"
11
12# Output: true
13
14# Check if all professors teach at least one course
15swift-aql evaluate --model university-data.xmi \
16 --expression "university.departments.professors->forAll(p | p.teaches->notEmpty())"
17
18# Output: true

Step 3

Combine quantifiers with filtering.

Combine exists and forAll with select and reject operations. This allows complex queries that both filter collections and test conditions.

Terminal
1# Combining quantifiers with filtering
2# Find departments where ALL professors have 10+ years experience
3swift-aql evaluate --model university-data.xmi \
4 --expression "university.departments->select(d |
5 d.professors->forAll(p | p.yearsExperience >= 10))"
6
7# Output: [Department(Physics)]
8
9# Find students enrolled in courses that have prerequisites
10swift-aql evaluate --model university-data.xmi \
11 --expression "university.students->select(s |
12 s.enrolledIn->exists(c | c.prerequisites->notEmpty()))"
13
14# Output: Students enrolled in at least one course with prerequisites
15
16# Find courses where all prerequisites are level 100 or 200
17swift-aql evaluate --model university-data.xmi \
18 --expression "university.courses->select(c |
19 c.prerequisites->notEmpty() and
20 c.prerequisites->forAll(p | p.level <= 200))"
21
22# Output: Courses with only introductory prerequisites

Step 4

Use quantifiers in nested contexts.

Apply quantifier operations to collections obtained through navigation. This enables deep queries that test conditions across multiple levels of the model.

Terminal
1# Nested quantifier operations
2# Find departments where at least one professor teaches
3# a course that has prerequisites
4swift-aql evaluate --model university-data.xmi \
5 --expression "university.departments->select(d |
6 d.professors->exists(p |
7 p.teaches->exists(c | c.prerequisites->notEmpty())))"
8
9# Output: Departments with professors teaching advanced courses
10
11# Check if all departments have at least one experienced professor
12swift-aql evaluate --model university-data.xmi \
13 --expression "university.departments->forAll(d |
14 d.professors->exists(p | p.yearsExperience >= 10))"
15
16# Output: true
17
18# Find students whose all courses have 4 credits
19swift-aql evaluate --model university-data.xmi \
20 --expression "university.students->select(s |
21 s.enrolledIn->notEmpty() and
22 s.enrolledIn->forAll(c | c.credits = 4))"
23
24# Output: Students enrolled only in 4-credit courses

Section 4

Advanced Filtering Patterns

Advanced filtering combines multiple operations, uses nested conditions, and applies filters at different levels of the model hierarchy.

These patterns are essential for complex model queries and form the foundation for sophisticated model analysis and validation.

Step 1

Chain multiple filter operations.

Chain select and reject operations to apply multiple filters in sequence. Each operation works on the result of the previous operation.

Terminal
1# Chaining multiple filter operations
2# First select high performers, then reject those in year 1
3swift-aql evaluate --model university-data.xmi \
4 --expression "university.students
5 ->select(s | s.grade >= 85)
6 ->reject(s | s.year = 1)"
7
8# Output: [Student(Alex, year 3), Student(Chris, year 4),
9# Student(Hannah, year 4), Student(Julia, year 3)]
10
11# Select CS majors, then filter to those with 80+ grades
12swift-aql evaluate --model university-data.xmi \
13 --expression "university.students
14 ->select(s | s.major.name = 'Computer Science')
15 ->select(s | s.grade >= 80)"
16
17# Output: [Student(Alex, 92.5), Student(Chris, 88.5), Student(Fiona, 82.0)]

Step 2

Filter collections of collections.

When working with collections that contain other collections, apply filtering at the appropriate level. Use flatten() when needed to work with flattened results.

Terminal
1# Filtering nested collections
2# Get all courses from departments, then filter to 4-credit courses
3swift-aql evaluate --model university-data.xmi \
4 --expression "university.departments.offeredCourses
5 ->select(c | c.credits = 4)"
6
7# Working with courses students are enrolled in
8swift-aql evaluate --model university-data.xmi \
9 --expression "university.students
10 ->select(s | s.grade >= 90)
11 .enrolledIn
12 ->flatten()
13 ->asSet()"
14
15# Output: Unique set of courses taken by high-achieving students
16
17# Filter professors' courses to advanced level only
18swift-aql evaluate --model university-data.xmi \
19 --expression "university.departments.professors
20 ->collect(p | p.teaches->select(c | c.level >= 300))
21 ->flatten()"
22
23# Output: All 300+ level courses taught by any professor

Step 3

Create custom filtering predicates.

Build reusable filtering logic by combining conditions in meaningful ways. This makes queries more readable and maintainable.

Terminal
1# Building reusable filtering predicates
2# Define meaningful conditions for readability
3
4# "High achiever" = grade >= 90 and year >= 3
5swift-aql evaluate --model university-data.xmi \
6 --expression "let highAchiever = (s : Student) | s.grade >= 90 and s.year >= 3
7 in university.students->select(highAchiever)"
8
9# Output: [Student(Alex, 92.5, year 3), Student(Julia, 96.5, year 3)]
10
11# "Experienced professor" = yearsExperience >= 15
12swift-aql evaluate --model university-data.xmi \
13 --expression "university.departments.professors
14 ->select(p | p.yearsExperience >= 15)"
15
16# Output: [Professor(Dr Alice Chen, 15), Professor(Dr David Lee, 20),
17# Professor(Dr Frank Taylor, 18)]
18
19# "Advanced course" = level >= 300 and has prerequisites
20swift-aql evaluate --model university-data.xmi \
21 --expression "university.courses
22 ->select(c | c.level >= 300 and c.prerequisites->notEmpty())"
23
24# Output: Advanced courses with prerequisites

Step 4

Combine filtering with other operations.

Use filtering as part of larger query pipelines. Combine with operations like collect, size, and arithmetic to create comprehensive model analyses.

Terminal
1# Combining filtering with other operations
2# Count students with each grade range
3swift-aql evaluate --model university-data.xmi \
4 --expression "let excellent = university.students->select(s | s.grade >= 90)->size(),
5 good = university.students->select(s | s.grade >= 80 and s.grade < 90)->size(),
6 pass = university.students->select(s | s.grade >= 60 and s.grade < 80)->size(),
7 fail = university.students->select(s | s.grade < 60)->size()
8 in 'Excellent: ' + excellent + ', Good: ' + good + ', Pass: ' + pass + ', Fail: ' + fail"
9
10# Output: "Excellent: 4, Good: 2, Pass: 3, Fail: 1"
11
12# Average grade of CS majors
13swift-aql evaluate --model university-data.xmi \
14 --expression "let csStudents = university.students->select(s | s.major.code = 'CS')
15 in csStudents->collect(s | s.grade)->sum() / csStudents->size()"
16
17# Output: Average grade for Computer Science students
18
19# Total credits of courses taught by experienced professors
20swift-aql evaluate --model university-data.xmi \
21 --expression "university.departments.professors
22 ->select(p | p.yearsExperience >= 15)
23 .teaches
24 ->flatten()
25 ->asSet()
26 ->collect(c | c.credits)
27 ->sum()"
28
29# Output: Total credit hours

Check Your Understanding

Question 1 of 4

What does students->select(s | s.grade >= 85) return?

Question 2 of 4

What’s the difference between select and reject?

Question 3 of 4

When would you use exists instead of select?

Question 4 of 4

What does courses->forAll(c | c.credits >= 3) return?

Collection Operations

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