Cardinality Many

Most attributes hold a single value per entity — :db.cardinality/one. But :pokemon/type is declared :db.cardinality/many, meaning an entity can have multiple values for the same attribute.

In the schema this looks like:

{:db/ident :pokemon/type, :db/valueType :db.type/string, :db/cardinality :db.cardinality/many}

The consequence for queries is important: binding a cardinality/many attribute produces one result row per value. Let's see it in action — run this query and notice how Bulbasaur appears twice:

[:find ?name ?type :where [?e :pokemon/name ?name] [?e :pokemon/type ?type] (or [?e :pokemon/name "Bulbasaur"] [?e :pokemon/name "Charmander"])]

Bulbasaur has two type values (Grass and Poison) so it produces two rows. Charmander is pure Fire so it produces one.

Finding dual-type Pokemon

We can use the multi-row behaviour to our advantage. By joining :pokemon/type to itself under two different variable names, we get all pairs of types on the same entity. Filtering with not= keeps only the pairs where the two values differ — that is, entities that carry at least two distinct types:

[:find ?name :where [?e :pokemon/name ?name] [?e :pokemon/type ?type1] [?e :pokemon/type ?type2] [(not= ?type1 ?type2)]]

Because :find returns a set of tuples, each name appears only once even though many (?type1, ?type2) combinations matched.

Counting values with aggregation

We can count how many type values each Pokemon has by using the count aggregate in :find. This is a preview of the next chapter — for now just observe that count collapses all the type rows for one entity into a single number:

[:find ?name (count ?type) :where [?e :pokemon/name ?name] [?e :pokemon/type ?type]]

Pokemon with a count of 2 are dual-typed. Those with 1 are single-typed. You can sort by the count column in the results to spot the dual-types quickly.

Try: Modify the dual-type query to also return ?type1 and ?type2 in :find to see which type combinations appear. Or change the or filter in the first query to show Bulbasaur and Pikachu side by side.

Previous | Next