Is there any way to use exists with a variable $p to refer it and use it in action?
I want to check if exists an object in my Working Memory, with exists to avoid the rule match more than once, but I want to save the reference to the object matched so I could use it in action.
Example what I want:
package test;
unit TestUnit;
rule "test_rule"
when
exists /test/cityList[$id : id,name=="Washington"]
then
System.out.println("there is one result id"+$id);
end
rule unit:
public class TestUnit implements RuleUnitData {
private final DataStore<TestRule> test;
public TestUnit() {
this(DataSource.createStore());
}
public TestUnit(DataStore<TestRule> test) {
this.test = test;
}
}
POJO:
public class TestRule {
private Long id;
private List<City> cityList;
}
public class City {
private Long id;
private String name;
}
Any idea or alternative to do it?
I tried run the code:
package test;
unit TestUnit;
rule "test_rule"
when
exists /test/cityList[$id : id,name=="Washington"]
then
System.out.println("there is one result id"+$id);
end
but results : text=$id cannot be resolved to a variable
then I tried in another way:
package test;
unit TestUnit;
rule "test_rule"
when
/test/cityList[$id : id]
exists /test/cityList[name=="Washington"]
then
System.out.println("there is one result id"+$id);
end
but it execute more then one times
Is there any way to use exists with a variable $p to refer it and use it in action?
No, because exists
tests that there exists at least one record that matches your condition. If there are three, which would you expect to be assigned to $p
?
(That's a rhetorical question, because it would be indeterminate. There is no guaranteed order to how Drools checks members in a collection.)
I'll go over your options in more detail below, but in general:
exists
when you want to test that there is at least one record in working memory that meets your conditions, but you're not particularly interested in the details.
not
predicate that's the negative analog of exists
when you want to verify there is nothing in working memory that meets your conditions.exists
). So if there are 3 cities called Washington, the rule will trigger three times, and $p
will be assigned to separate city when its their turn.collect
and verify the length of your result. If there is exactly one city Washington, your rule will trigger and you can get a direct reference to that city. If there is more than one city, the rule will not trigger at all.As you've discovered, you can only use the exists
predicate if you want to determine presence of a matching record.
(I'm going to use the slightly older syntax with parentheses in my example instead of the newer one with slashes; the concepts are the same.)
rule "Fire exactly once if there is at least one city called 'Washington'"
when
exists( City( name == "Washington" ) from cityList )
then
System.out.println("There exists at least one city Washington.")
end
However, you do not have a reference to that City instance, so you can't print its ID. After all, what if you had two cities called Washington? Which would you expect to match? It would be indeterminate. The point of exists
is only to test for existence.
If you want to trigger for every city called Washington, the solution is to simply remove exists
.
rule "Fire for each city called 'Washington'"
when
City( $id: id, name == "Washington" ) from cityList
then
System.out.println("Found Washington with id " + $id)
end
If you had three cities called Washington in your list, this would fire and print 3 times, once for each ID.
If you want your rule to fire if there is only exactly one city called Washington, you'll need to collect all the qualifying cities and verify that there is exactly one item in that list.
rule "Fire if there is only exactly 1 city called 'Washington'"
when
List( size == 1 ) from collect( City( name == "Washington" ) from cityList)
then
System.out.println("There is exactly one city called Washington")
end
In this case, you end up with a List, so you can easily assign a reference to that, pull the City out, and reference its id and other values.