Validating uniqueness across two properties

This recipe shows how to enforce uniqueness across a combination of properties, so that individual values can repeat but the same pair cannot appear twice.

When to use this approach

Use composite uniqueness when a single property is not enough to identify a duplicate. A Membership where the same user can belong to many organizations and the same organization can have many users, but a given user-and-organization pair must be unique. A Schedule where the same room can be booked on many dates and the same date can have many rooms, but a given room-and-date pair must not repeat.

Individual vs composite uniqueness

Setting unique to "true" on a property enforces individual uniqueness — no two items of the governed type may share the same value for that property:

<meta itemprop="unique" content="true">

Setting unique to a shared group name instead of "true" creates a composite uniqueness constraint. Properties that share the same group name form a composite key: the combination of their values must be unique, even though each value alone may repeat.

A worked example

A Membership schema needs to prevent the same user from being added to the same organization twice. Neither user-id nor org-id should be individually unique — each value repeats across many memberships. The combination must be unique.

Give both properties the same unique group name:

<div itemscope itemtype="https://pagelove.org/Schema">
  <meta itemprop="type" content="https://example.com/Membership">
  <ul>
    <li itemprop="property" itemscope itemtype="https://pagelove.org/Property">
      <meta itemprop="name" content="user-id">
      <meta itemprop="type" content="https://schema.host/Text">
      <meta itemprop="cardinality" content="1..1">
      <meta itemprop="unique" content="membership-pair">
    </li>
    <li itemprop="property" itemscope itemtype="https://pagelove.org/Property">
      <meta itemprop="name" content="org-id">
      <meta itemprop="type" content="https://schema.host/Text">
      <meta itemprop="cardinality" content="1..1">
      <meta itemprop="unique" content="membership-pair">
    </li>
  </ul>
</div>

With this schema in place:

Uniqueness is enforced atomically with the write. There is no window in which a duplicate can slip through.

See also