You are viewing the documentation for Blueriq 17. Documentation for other versions is available in our documentation directory.
Learn more about the collection functions EXISTS, EACH, ALL, COLLECT FROM WHERE, COLLECT FROM NAMED WHERE, COLLECT, UNPACK, LIST, SIZE, UNIQUE, SUBSET OF, UNION, INTERSECTION, DIFFERENCE, SYMMETRIC_DIFFERENCE.
Overview
Function | Description |
---|---|
EXISTS | Determines whether an instance of a specified entity exists, optionally meeting certain criteria. |
EACH | Determines whether all instances of a specified entity meet a certain criteria. |
ALL | Creates a collection of all instances of a specified entity. |
COLLECT FROM [WHERE] | Creates a collection of entity or attribute instances (meeting certain criteria). |
COLLECT FROM NAMED [WHERE] | Version of COLLECT FROM [WHERE] for complex nested selections with an alias. |
UNPACK | Extracts the value from a single valued collection or list. Is the inverse of the LIST function. |
LIST | Creates a list based on a value. Is the inverse of the UNPACK function. |
SIZE | Determines the size of a collection. |
UNIQUE | Filters duplicate items from a collection resulting from a subexpression in a larger expression. |
SUBSET OF | Returns TRUE if the items in a collection are all present in another collection. |
UNION | Adds two collections of the same base type to a new collection. |
INTERSECTION | Determines the intersection of two collections. |
DIFFERENCE | Determines the difference between 2 collections. Returns a collection containing all the items from collection1 that are not present in collection2. |
SYMMETRIC_DIFFERENCE | Determines the symmetric difference between two collections. Returns a collection with the elements of the provided collections which are in either one of the collections, but not in both. |
A note on collections and duplicates.
Functions
EXISTS
Determines whether an instance of a specified entity exists, optionally meeting certain criteria.
Syntax
EXISTS instances [ WHERE ( condition ) ]
- instances - Instances to search.
- condition - boolean expression that represents the criterion the instance has to meet.
Return type
- boolean
Examples
Suppose the following data model.
Person.name | Person.gender | Person.age |
---|---|---|
“Kim” | ? | 23 |
“Rick” | “m” | 35 |
“Bob” | “m” | 42 |
“John” | “m” | 19 |
“Mary” | “f” | 33 |
Expression | Result | Type |
---|---|---|
EXISTS Person | TRUE | boolean |
EXISTS Person WHERE ( Person.age < 18 ) | FALSE | boolean |
EXISTS Person WHERE ( Person.gender = "m" AND Person.age > 35 ) | TRUE | boolean |
EXISTS Person WHERE ( Person.gender = "f" AND Person.age < 25 ) | UNKNOWN | boolean |
EXISTS Person WHERE ( Person.age < 25 AND Person.gender = "f" ) | FALSE | boolean |
EXISTS Person WHERE ( Person.gender = ? ) | TRUE | boolean |
Please note that you can use a COLLECT expression as well for collecting instances for which the EXISTS should hold. E.g., EXISTS (COLLECT Person FROM ALL Person WHERE (Person.gender = "f")) WHERE ( Person.age < 25 ).
In case that the list of instances for which the EXISTS should hold is an EMPTY list, then the EXISTS expression returns FALSE.
EACH
Determines whether all instances of a specified entity meet a certain criteria.
Syntax
EACH instances WHERE ( condition )
- instances - A collection of instances to search.
- condition - Boolean expression that represents the criterion the instance has to meet.
Return type
- Boolean
Examples
Suppose the following data model.
Person.name | Person.gender | Person.age |
---|---|---|
“Kim” | ? | 23 |
“Rick” | “m” | 35 |
“Bob” | “m” | 42 |
“John” | “m” | 19 |
Expression | Result | Type |
---|---|---|
EACH Person WHERE ( Person.age < 18 ) | FALSE | Boolean |
EACH Person WHERE ( Person.age > 18 ) | TRUE | Boolean |
EACH Person WHERE ( Person.age < 20 ) | FALSE | Boolean |
EACH Person WHERE ( Person.gender = "m" OR Person.age > 35 ) | UNKNOWN | Boolean |
EACH Person WHERE ( Person.gender = "m" OR Person.age > 20 ) | TRUE | Boolean |
Please note that you can use a COLLECT expression as well for collecting instances for which the EACH should hold. E.g., EACH (COLLECT Person FROM ALL Person WHERE (Person.gender = "f")) WHERE ( Person.age < 25 ).
In case that the list of instances for which the EACH should hold is an EMPTY list, then the EACH expression returns TRUE.
ALL
Creates a collection of all instances of a specified entity.
Syntax
ALL entity
- entity - Entity of which to collect all its instances.
Return type
- collection of entity instances
Examples
Suppose the following data model. The Parent
and Child
entities both have Person
as base entity.
Parent instance | Child instance |
---|---|
Parent_1 | Child_1 |
Parent_1 | Child_2 |
Parent_1 | Child_3 |
Parent_2 | Child_4 |
Expression | Result | Type |
---|---|---|
ALL Parent | [ Parent_1 , Parent_2 ] | Collection of Parent instances |
ALL Child | [ Child_1 , Child_2 , Child_3 , Child_4 ] | Collection of Child instances |
ALL Person | [ Parent_1 , Parent_2 , Child_1 , Child_2 , Child_3 , Child_4 ] | Collection of Person instances |
COLLECT FROM [WHERE]
Creates a collection of entity or attribute instances (meeting certain criteria).
Syntax
COLLECT entity | attribute FROM collection [ WHERE ( expression ) ]
- entity or attribute - Entity or attribute to collect.
- collection - A collection of entity instances.
- expression - Boolean expression that represents the criterion the instance has to meet.
Return type
- collection of entity instances
- collection of attribute values
A collection contains no duplicates. Intermediary COLLECT
expressions can contain duplicates however, please see the note on collections and duplicates.
Examples
Suppose the following model. Entity Teacher
has a multivalued relation with entity Child
via the relation Teacher.teaches_Children
.
Teacher instance | Child instance | Child.name | Child.hobbies |
---|---|---|---|
Teacher_1 | Child_1 | “Kim” | “Reading”, “Dancing” |
Teacher_1 | Child_2 | “Rick” | “Tennis”, “Dancing” |
Teacher_1 | Child_3 | “Bob” | “Painting”, “Basketball”, “Reading” |
Teacher_2 | Child_1 | “Kim” | “Reading”, “Dancing” |
Teacher_2 | Child_3 | “Bob” | “Painting”, “Basketball”, “Reading” |
Teacher_2 | Child_4 | “Mary” | “Football” |
Expression | Result | Type |
---|---|---|
COLLECT Child.name FROM ALL Child | [ “Kim”, “Rick”, “Bob”, “Mary” ] | String (multivalued) |
COLLECT Child FROM Teacher[Teacher_2].teaches_Children | [ Child_1, Child_3, Child_4 ] | Collection of Child instances |
COLLECT Child.hobbies FROM Teacher[Teacher_1].teaches_Children | [ “Reading”, “Dancing”, “Tennis”, “Painting”, “Basketball” ] | String (multivalued) |
COLLECT Child.name FROM ALL Child | [ “Kim”, “Bob” ] | String (multivalued) |
COLLECT Child.hobbies FROM ALL Child WHERE ( Child.name = "Mary" ) | [ “Football” ] | String (multivalued) |
COLLECT FROM NAMED [WHERE]
Version of the COLLECT FROM [WHERE] function for complex nested selections with an alias.
Syntax
COLLECT entity | attribute FROM collection NAMED alias [ WHERE ( expression ) ]
- entity or attribute - Entity or attribute to collect. This should contain the alias, e.g. alias.Name.
- collection - A collection of entity instances.
- alias - A name for the collection.
- expression - Boolean expression that represents the criterion the instance has to meet.
Return type
- collection of entity instances
- collection of attribute values
A collections contains no duplicates. Intermediary COLLECT
expressions can contain duplicates however, please see the note on collections and duplicates.
Examples
Suppose the following model with only instances of entity Person
. Person.hasChildren
is a relation from Person to Person.
Person instance | Person.Name | Person.Age | Person.hasChildren |
---|---|---|---|
Person_1 | “Kim” | 16 | |
Person_2 | “Rick” | 38 | Person_3, Person_5 |
Person_3 | “Bob” | 8 | |
Person_4 | “Julia” | 42 | Person_1 |
Person_5 | “Sam” | 3 | |
Person_6 | “Joan” | 34 | Person_3, Person_5 |
To retrieve all the parent names, we use this expression:
COLLECT Parent.name FROM COLLECT Person FROM ALL Person WHERE ( Person.hasChildren != ? ) NAMED Parent
This expression results in “Rick”, “Julia” and “Joan”.
To retrieve all children names, we use this expression:
COLLECT Child FROM ( COLLECT Person.hasChildren FROM ALL Person WHERE ( Person.hasChildren != ? ) ) NAMED Child
This expression results in a collection of three instances of Person
(i.e Person_1
, Person_3
and Person_5
, with names Kim, Bob and Sam).
To retrieve all children younger than 15, we use this expression:
COLLECT Child FROM ( COLLECT Person.hasChildren FROM ALL Person WHERE ( Person.hasChildren != ? ) ) NAMED Child WHERE ( Child.Age < 15 )
This expression results in a collection of two instances of Person
(i.e Person_3
and Person_5
, with names Bob and Sam).
To retrieve the children’s names with a parent older than 40 years:
COLLECT Child.Name FROM ( COLLECT Person.hasChildren FROM ALL Person WHERE ( Person.hasChildren != ? AND Person.Age > 40 ) ) NAMED Child
This expression results in a collection with only the name “Kim”.
You can make it as complex as you like, for example:
COLLECT Child.Name FROM ( COLLECT Parent.hasChildren FROM ( COLLECT Person FROM ALL Person WHERE ( Person.hasChildren != ? ) ) NAMED Parent WHERE ( Parent.Age > 40 ) ) NAMED Child WHERE ( Child.Age < 18 )
This expression results also in a collection with only the name “Kim”.
In some occasions, a local variable could be a good alternative for using an alias. E.g. if you want a collection of all persons except the person that is currently active, this would be simple and transparent:
thisPerson := Person ; COLLECT Person FROM ALL Person WHERE ( Person != thisPerson )
UNPACK
Extracts the value from a single valued collection or list. Is the inverse of the LIST function.
Syntax
UNPACK ( collection/list )
- collection/list - A collection or list of one entity or attribute instance.
Return type
- entity instance
- attribute value of any type
Examples
Suppose the following data model.
Person.name | Person.SequenceNumber |
---|---|
“Bob” | 654 |
“Jane” | 523 |
“Mary” | 667 |
“Rick” | 500 |
“Ron” | 490 |
“Jenny” | 765 |
UNPACK ( COLLECT Person.name FROM ALL Person WHERE ( Person.SequenceNumber = MIN ( COLLECT Person.SequenceNumber FROM ALL Person ) ) )
= “Ron”- In case a second entry "Ron","490" exists, the expression
UNPACK ( COLLECT Person.name FROM ALL Person WHERE ( Person.SequenceNumber = MIN ( COLLECT Person.SequenceNumber FROM ALL Person ) ) )
will fail, because theUNPACK
cannot resolve a list with two elements. To solve this theUNIQUE
function has to be used:UNPACK ( UNIQUE ( COLLECT Person.name FROM ALL Person WHERE ( Person.SequenceNumber = MIN ( COLLECT Person.SequenceNumber FROM ALL Person ) ) ) )
= "Ron". UNPACK ( COLLECT Person.name FROM ALL Person WHERE ( Person.SequenceNumber = MAX ( COLLECT Person.SequenceNumber FROM ALL Person ) ) )
= “Jenny”
LIST
Creates a list based on a value. Is the inverse of the UNPACK function.
Syntax
LIST ( attribute/collection )
- attribute - An attribute of any data type.
- collection/list - A collection or list of values.
Return type
- a multivalued list with entries of any type
Examples
Expression | Result | Type |
---|---|---|
LIST ( "Blueriq" ) | [ "Blueriq" ] | String (multivalued) |
LIST ( 5 ) | [ 5 ] | Integer (multivalued) |
LIST ( ? ) | [] | Any (multivalued) |
Suppose the following data model.
Person.name | Person.SequenceNumber |
---|---|
“Bob” | 654 |
“Jane” | 523 |
“Mary” | 667 |
“Rick” | 500 |
“Ron” | 490 |
“Jenny” | ? |
LIST ( COLLECT Person.name FROM ALL Person ) = [ "Bob" , "Jane" , "Mary" , "Rick" , "Ron" , "Jenny" ]
- In this example the
LIST
function adds no value, as the result of theCOLLECT
is already a list.
- In this example the
LIST ( COLLECT Person.SequenceNumber FROM ALL Person ) = []
- As Jenny has an unknown sequence number, the result of the
COLLECT
expression is?
. TheLIST
function creates an empty list in case the parameter has?
value.
- As Jenny has an unknown sequence number, the result of the
SIZE
Determines the size of a collection.
Syntax
SIZE ( collection )
- collection - A collection of attribute or entity instances. This can be an expression or a relation attribute for instance.
Return type
- integer
Example
Suppose you have a Parent
and a Child
entity, where Parent
has a multivalued relation with Child
via the relation Parent.has_Children
. With this model the following instances are created:
Parent instance | Child instance | Child.name | Child.hobbies |
---|---|---|---|
Parent_1 | Child_1 | “Kim” | “Reading”, “Dancing” |
Parent_1 | Child_2 | “Rick” | “Tennis”, “Dancing” |
Parent_1 | Child_3 | “Bob” | “Painting”, “Basketball”, “Reading” |
Parent_2 | Child_4 | “Mary” | “Football” |
Then:
Active instance | Expression | Result | Type |
---|---|---|---|
Parent_1 | SIZE ( Parent.has_Children ) | 3 | Integer |
Parent_2 | SIZE ( Parent.has_Children ) | 1 | Integer |
none | SIZE ( Parent.has_Children ) | Error | |
Child_1 | SIZE ( Child.hobbies ) | 2 | Integer |
Child_3 | SIZE ( Child.hobbies ) | 3 | Integer |
Child_4 | SIZE ( Child.hobbies ) | 1 | Integer |
SIZE( ? ) | 0 | Integer |
SIZE and COUNT are similar except for ?:
SIZE ( ? ) results in 0, while COUNT ( ? ) results in ?
UNIQUE
Filters duplicate items from a collection resulting from a subexpression in a larger expression. An expression resulting in a collection never contains duplicate values. A subexpression with the COLLECT
statement however, can contain duplicates. See the note on collections and duplicates for more info.
Syntax
UNIQUE ( collection )
- collection - A collection of attribute or entity instances.
Return type
- collection
Examples
Suppose the following model.
Person instance | Person.name |
---|---|
Person_1 | “Kim” |
Person_2 | “Rick” |
Person_3 | “Bob” |
Person_4 | “Rick” |
Expression | Result | Type | Note |
---|---|---|---|
COLLECT Person.name FROM ALL Person | [ "Kim" , "Rick" , "Bob" ] | String (multivalued) | A result never contains duplicate values |
SIZE ( COLLECT Person.name FROM ALL Person ) | 4 | Integer | A subexpression can contain duplicate values |
SIZE ( UNIQUE ( COLLECT Person.name FROM ALL Person ) ) | 3 | Integer | The collection holds three unique values |
SUBSET OF
Returns TRUE
if the items in a collection are all present in another collection.
Syntax
collection1 SUBSET OF collection2
- collection1 - The collection that is tested to be a subset of the second collection.
- collection2 - The collection that is tested to hold all the items in the first collection.
Return type
- boolean
Venn diagram
Examples
Expression | Result | Type | Note |
---|---|---|---|
( 'a' , 'b' , 'c' ) SUBSET OF ( 'a' , 'b' , 'c' , 'd' ) | TRUE | boolean | |
( 'a' , 'b' , 'c' , 'd' ) SUBSET OF ( 'a' , 'b' , 'c' ) | FALSE | boolean | |
Person.hobbies SUBSET OF [ "Tennis" , "Soccer" , "Music" ] Given Person.hobbies = [ "Tennis" , "Soccer" ] | TRUE | boolean | |
Person.hobbies SUBSET OF [ "Tennis" , "Soccer" , "Music" ] Given Person.hobbies = [ ? ] | ? | boolean | |
Person.hobbies SUBSET OF [ "Tennis" , "Soccer" , ? ] Given Person.hobbies = [ "Tennis" , "Soccer" ] | FALSE | boolean | [ "Tennis" , "Soccer" , ? ] evaluates to [ ? ] Person.hobbies SUBSET OF [ ? ] = FALSE |
( 'a' , 'b' , 'c' ) SUBSET OF ( [ 'a' , 'b' , 'c' , 'd' ] ) | Error | ||
1 SUBSET OF Address.Numbers Given Adress.Numbers = ? | FALSE | boolean |
Values between single quotes are considered value list items. For backwards compatibility reasons, a comma separated sequence of value list items is treated as a collection. That's why there is no need to enclose the values between square brackets. In fact if you do add the square brackets you create a matrix rather than a list.
UNION
Adds two collections of the same base type to a new collection.
Syntax
UNION ( collection1 , collection2 )
- collection1 - First collection to be added to the new collection.
- collection2 - Second collection to be added to the new collection.
Return type
- collection
Venn diagram
Examples
Suppose you have a Parent
and a Child
entity, where Parent
has a multivalued relation with Child
via the relation Parent.has_Children
. With this model the following instances are created:
Parent instance | Child instance | Child.name | Child.age | Child.hobbies |
---|---|---|---|---|
Parent_1 | Child_1 | “Kim” | 11 | “Reading”, “Dancing” |
Parent_1 | Child_2 | “Rick” | 9 | “Tennis”, “Dancing” |
Parent_1 | Child_3 | “Bob” | ? | “Painting”, “Basketball”, “Reading” |
Parent_2 | Child_4 | “Mary” | 10 | “Football” |
Expression | Result | Type | Remarks |
---|---|---|---|
UNION ( Parent[Parent_1].has_Children , Parent[Parent_2].Has_Children ) | [ Child_1, Child_2 , Child_3, Child_4 ] | Collection of Child instances | |
UNION ( Parent[Parent_1].has_Children.name , Parent[Parent_2].Has_Children.name ) | [ “Kim”, “Rick”, “Bob”, “Mary” ] | String (multivalued) | |
UNION ( Child[Child_2].hobbies , "Reading" ) | [ “Tennis”, “Dancing”, “Reading” ] | String (multivalued) | |
UNION ( Child[Child_1].hobbies , Child[Child_2].hobbies ) | [ “Reading”, “Dancing”, “Tennis” ] | String (multivalued) | |
UNION( Child[Child_3].age, [1, 2] ) | UNKNOWN | Integer (multivalued) | Since the age of Child_3 is unknown, the expression will result in unknown. |
UNION( LIST(Child[Child_3].age), [1, 2] ) | [1, 2] | Integer (multivalued) | The result of LIST(Child[Child_3].age) is an empty list. |
INTERSECTION
Determines the intersection of two collections. It returns a collection containing the items that are present in both specified collections.
Syntax
INTERSECTION ( collection1 , collection2 )
- collection1, collection2 - Collections to be intersected. These collections must be of the same base type.
Return type
- collection
Venn diagram
Examples
Suppose the following model. Entity Teacher
has a multivalued relation with entity Child
via the relation Teacher.teaches_Children
.
Teacher instance | Child instance | Child.name | Child.hobbies |
---|---|---|---|
Teacher_1 | Child_1 | “Kim” | “Reading”, “Dancing” |
Teacher_1 | Child_2 | “Rick” | “Tennis”, “Dancing” |
Teacher_1 | Child_3 | “Bob” | “Painting”, “Basketball”, “Reading” |
Teacher_2 | Child_1 | “Kim” | “Reading”, “Dancing” |
Teacher_2 | Child_3 | “Bob” | “Painting”, “Basketball”, “Reading” |
Teacher_2 | Child_4 | “Mary” | “Football” |
Expression | Result | Type |
---|---|---|
INTERSECTION ( Teacher[Teacher_1].teaches_Children , Teacher[Teacher_2].teaches_Children ) | [ Child_1 , Child_3 ] | Collection of Child instances |
INTERSECTION ( Teacher[Teacher_1].teaches_Children.name , Teacher[Teacher_2].teaches_Children.name ) | [ "Kim" , "Bob" ] | String (multivalued) |
INTERSECTION ( Child[Child_1].hobbies , Child[Child_3].hobbies ) | [ "Reading" ] | String (multivalued) |
INTERSECTION ( Child[Child_2].hobbies , Child[Child_3].hobbies ) | [ ] | String (multivalued) |
INTERSECTION( ?, [ 1, 2 ] ) | UNKNOWN | Integer (multivalued) |
DIFFERENCE
Determines the difference between 2 collections. Returns a collection containing all the items from collection1 that are not present in collection2.
Syntax
DIFFERENCE ( collection1 , collection2 )
- collection1, collection2 - Collections to be compared. These collections must be of the same base type.
Return type
- collection
Venn diagram
Examples
Expression | Result | Type |
---|---|---|
DIFFERENCE ( [ "a", "b", "c"] , [ "c", "d", "e" ] ) | [ "a" , "b" ] | String (multivalued) |
DIFFERENCE ( [ "nv" , "bv" ] , [ "NV" ] ) | [ "bv" ] | String (multivalued) |
DIFFERENCE ( 1 , 1 ) | [ ] | Integer (multivalued) |
DIFFERENCE( [ 1, 2 ], ? ) | ? | Integer (multivalued) |
SYMMETRIC_DIFFERENCE
Determines the symmetric difference between two collections. Returns a collection with the elements of the provided collections which are in either one of the collections, but not in both.
Syntax
SYMMETRIC_DIFFERENCE ( collection1 , collection2 )
- collection1, collection2 - Collections to be compared. These collections must be of the same base type.
Return type
- collection
Venn diagram
Examples
Expression | Result | Type |
---|---|---|
SYMMETRIC_DIFFERENCE ( [ "a" , "b" , "c" ] , [ "c" , "d" , "e" ] ) | [ "a", "b", "d", "e" ] | String (multivalued) |
SYMMETRIC_DIFFERENCE ( [ "nv" , "bv" ] , [ "NV" ] ) | [ "bv" ] | String (multivalued) |
SYMMETRIC_DIFFERENCE ( 1 , 1 ) | [ ] | Integer (multivalued) |
A note on collections and duplicates
An expression resulting in a collection does not contain duplicates. Please be aware however, that intermediary results of a COLLECT
statement can contain duplicates. You have to be aware of this when using the SIZE
or UNPACK
function, or when using TSL.
This is best illustrated with the following examples.
Person instance | Person.Name | Person.Age |
---|---|---|
Person_1 | Kim | 24 |
Person_2 | Rick | 25 |
Person_3 | Bob | 25 |
Expression | Result | Type | Note |
---|---|---|---|
COLLECT Person.Age FROM ALL Person | [ 24 , 25 ] | String (multivalued) | |
SIZE ( COLLECT Person.Age FROM ALL Person ) | 3 | Integer | The intermediary collection is [ 24, 25, 25 ] |
TSL: The ages present are: [[[ COLLECT Person.Age FROM ALL Person ]]]. | The ages present are: 24, 25, 25. | String | The intermediary collection is [ 24, 25, 25 ] |
SIZE ( UNIQUE ( COLLECT Person.Age FROM ALL Person ) ) | 2 | Integer | The duplicates in the intermediary collection are filtered by the UNIQUE function |
Now an example with the UNPACK function. We leave out the first instance from the previous example.
Person instance | Person.Name | Person.Age |
---|---|---|
Person_2 | Rick | 25 |
Person_3 | Bob | 25 |
Expression | Result | Type | Note |
---|---|---|---|
COLLECT Person.Age FROM ALL Person | [ 25 ] | Integer (multivalued) | |
UNPACK ( COLLECT Person.Age FROM ALL Person ) | Error | The collection contains 2 elements [ 25 , 25 ] | |
UNPACK ( UNIQUE ( COLLECT Person.Age FROM ALL Person ) ) | 25 |
Only the intermediary results of a COLLECT
statement can contain duplicates. The functions UNIQUE
, UNION
, INTERSECTION
, DIFFERENCE
and SYMMETRIC_DIFFERENCE
always return collections without duplicates.
27 Comments
Han Joosten
Han Joosten
At the section UNPACK, examples are missing, though the text suggests that they should be there.
Unknown User (m.gulpers)
Fixed it; it had gone missing somehow
Sven Monshouwer
Within our project we are trying to check the number of seconds a migration of aggregates takes before it is done for a specific set. We want to add the results to a multivalued attribute using a UNION statement. Is it true that the UNION statement only stores unique values in the string? If we use the same for adding timestamps it works fine since they are unique.
Is it possible to use a UNION statement to store all returned values even if they already exist in target attribute?
Geert Graat
No, it is not possible to store duplicate values using a UNION statement, as the result of a UNION will always filter out duplicates. See also this section: A note on collections and duplicates.
Rory Tans
Is it possible to expand this article with behaviour of functions and expected return values? When modelling we encountered that each function behaves differently in how many arguments it returns. For example:
Collect person.age from all person will result in [ 18 ]
Size(collect person.age from all person) will result in a 4
Union((Collect person.age from all person where person.category =1), Collect person.age from all person where person.category =2)) will result in [ 18 ]
Size(Union((Collect person.age from all person where person.category =1), Collect person.age from all person where person.category =2))) Will result in 3
As you can see, sometimes functions will result in a answer which isn't entirely expected. Why for example will Collect person.age from all person not return [ 18, 18, 18, 18 ]
If possible, please expand this article with how collections will be compressed. Sometimes the answer is obvious, but it might not always be apparent that size(union([ 18 ], [ 18, 18, 18 ])) will be 3 (instead of 1).
Han Joosten
It is allready there: Have a look at A note on collections and duplicates.
Rory Tans
Hey Han! I've seen this part, but I feel it's incomplete. For example, from reading this I wouldn't know what UNION's properties are.
Han Joosten
In general, the UNION and other collection functions are implemented as sets. As can be read in the note on collections and duplicates, intermediate results behave different, and cannot be trusted as being sets. I think it would be nice if the tooling would be fixed for this. Now, the Blueriq modeller has to cope with this.
Charley Gielkens
I noticed this remark:
This leads me to two questions:
Louis Wouters
Since it is treated as a value list item, a validation rule is triggered.
Entity.Attribute = 'ValueInDomain','ValueOutsideDomain' will give a validation error,
Entity.Attribute = ["ValueInDomain","ValueOutsideDomain"] will not.
Charley Gielkens
That would be really curious behavior as this would not allow you to get a negative result in a comparison. Only a TRUE or an error.
I've tried a simple expression in our debugbar:
As per your comment I would expect an error, however it just returns FALSE. This returns neither an error at runtime in the log nor a validation error at designtime.
Louis Wouters
That's not exactly what I meant. The domain check only makes sense if you compare it with an attribute. If it's an expression (like "a" in your example) it's an open domain. i.e. any value is possible as long as it has the correct datatype.
Charley Gielkens
Still just a valid FALSE if I do in the debugbar:
Where the the attribute has a valuelist containing both options after the =, but the value isnt ADP or VVB.
Louis Wouters
The domain validation I'm talking about is a studio-validation, so that won't affect the debug bar.I spoke too soon hereYour example uses valid domain values so no error is thrown. Nothing unusual there.
Charley Gielkens
So, I would have to give an attribute with a value list a value that is invalid in the actual value list, then compare it to a collection written to behave like a value list to get a validation error is what you're saying?
Louis Wouters
Try to evaluate: Dossier.Product = 'ADP','VVB','nonexistingproduct'
This will give an error since nonexistingproduct is not in your valuelist.
Dossier.Product = ['ADP','VVB','nonexistingproduct'] will evaluate to FALSE
Charley Gielkens
Aaaaaah. Now I get it Thanks for the clarification. This is not something I would understand from the way the documentation is currently written, nor do I find it intuitive.
Nienke Nobel
Hi! I'm looking for a way to determine whether all values from L1 can be found in L2 and the other way around, so basically the symettric difference, but with taking into account the duplicates. Is there any simple way to do this, without having to check every single value with the other list?
For example:
L1 = [1,2,3,3,4], L2 = [1,2,3,4,4] → Result should be either FALSE or a List [3,4] (so I can check the SIZE of the result)
L1 = [1,2,3,4,4], L2 = [1,2,3,4] → Result should be FALSE or a List [4]
L1 =[1,2,3,3,4], L2 = [3,2,4,3,1] → Result should be TRUE or an EMPTY LIST
Louis Wouters
I don't think there's an easy way to do it.
It might not be possible at all, since duplicates are removed as soon as an attribute value is derived.
Maybe if you tell the underlying problem that you are trying to solve, we can come up with a different approach.
Nienke Nobel
So the problem is as follows:
We have an application that has employments (entity) and a document that contains information about a set of employments (the "employments" on the documents are a different entity).
We have no certain way to match the employments from the document with the employments in the applictation. We do however want to know whether certain fields in the document are used in the application, as the document contains "the truth" about the applicants employments. A seperate check for every field is made, so we can inform the user where they have to review the data.
The problem we have here is the check for the Dutch KvK-number. We want to check whether all KvK-numbers that are mentioned in the document are being used in the application and that all KvK-numbers in the application can be found in the document. In it's simplest form this can be done without checking for duplicates. However if you have two seperate employments at the same employer (for example you have two different functions with different contracts at the same employer, or you are both employee and owner of a company), you will get duplicates in the KvK-numbers.
We would like to be able to check whether all KvK-numbers for all seperate employments in the document can be found in the application. If you have the rare case of 3 employments in your document where 2 of them have the same KvK-number ( 1,2,2 ), we want to make sure that you will also have 3 employments in your application where 2 of them will have the same KvK-number (1,2,2). 1,1,2 should not be allowed, because that doesn't agree with the information in the document.
This method would of course still fail if the user shuffles all numbers around, but that is an accepted risk as a result of not directly matching the employments in the document with the employments in the application.
Unknown User (a.jansen)
Hi, Louis Wouters, thanks for the great follow-up question, and Nienke Nobel , thanks for supplying some additional info. Could a relatively simple solution to your problem be to Text functions#CONCATENATE the KvK numbers alphabetically into a String attribute using a flow with repeat expression sorted alphabetically on the KvK numbers, and then comparing the 2 strings using Text functions#EQUALS ? If not, please let us know. We would gladly continue to think of alternate solutions.
Nienke Nobel
Hi Aäron. Thanks for the suggestion! This will probably work! Unfortunatly most of our checks are done "realtime" in decision tables", so this would deviate from that, and we will have to use a FlowOnRefresh. Unless you know a way to sort a List or String in an expression?
Nienke Nobel
New idea: Would it maybe be possible to COUNT all occurences for every value using FOREACH in both lists and say they have to be the same?
Louis Wouters
What I would do:
Make an attribute in Employment called "InDocument" with default expression:
ThisEmployment := Employment
COUNT( COLLECT Employment FROM ALL Employment WHERE( Employment.KvKNumber = ThisEmployment.KvKNumber ) )
=
COUNT( COLLECT EmploymentDocument FROM ALL EmploymentDocument WHERE( EmploymentDocument.KvKNumber = ThisEmployment.KvKNumber ) )
Then you can make an attribute like Document.Complete with default
EACH Employment WHERE( Employment.InDocument )
AND
COUNT( ALL EmploymentDocument ) = COUNT( ALL Employment )
Nienke Nobel
Thank you!
Unknown User (a.jansen)
Wow Louis Wouters, great stuff! Nienke Nobel: if somehow this still doesn't solve your problem or if you have any more interesting questions, puzzles or challenges, please let us know.