# 10: uniqueness constraint

If you're building a forum and want people to be able to like posts, you probably don't want to allow people to like the same post twice. If your schema is something like this:

| **like**  |
| --------- |
| `post-id` |
| `user-id` |

Then you probably have a constraint such that you can't have two records with the same `post-id` and `user-id`. How do you model this in Specmonstah? So far, we've seen schemas like this:

```scheme
(ns reifyhealth.specmonstah-tutorial.10
  (:require [reifyhealth.specmonstah.core :as sm]))
  
(def bad-schema
  {:user {:prefix :u}
   :post {:prefix :p}
   :like {:prefix      :l
          :spec        ::like
          :relations   {:post-id       [:post :id]
                        :created-by-id [:user :id]}}})
```

If you use this to generate ents, you'll end up in a disappointing situation:

```scheme
(defn ex-01
  []
  (sm/view (sm/add-ents {:schema bad-schema} {:like [[3]]})))
(ex-01)
```

![likes all reference the same post and user](https://4068685904-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LoN3fu4ydp8osDZFQch%2F-Lp0manTT3RYiCSFHC32%2F-Lp0pHLMpNc1NCFQN_Vu%2Fbad-schema.png?alt=media\&token=d167d809-24cd-429d-8112-38c4f34c909c)

All the likes reference the same `:post` (`:p0`) and `:user` (`:u0`). This happens because Specmonstah generates the minimal data needed to satisfy a query.

&#x20;To get Specmonstah to generate data that your database will accept, you introduce a *uniqueness constraint* in the schema:

```scheme
(def good-schema
  {:user {:prefix :u}
   :post {:prefix :p}
   :like {:prefix      :l
          :spec        ::like
          :relations   {:post-id       [:post :id]
                        :created-by-id [:user :id]}
          :constraints {:created-by-id #{:uniq}}}})
```

Notice the `:constraints` key at the bottom of the schema. This tells Specmonstah, "The `:created-by-id` relation of every `:like` should refer to a unique `:user`. If you generate multiple `:like`s, generate new `:user`s too until each like refers to a differ `:user`."

This schema will generate a graph that will satisfy your database's constraints:

```scheme
(defn ex-02
  []
  (sm/view (sm/add-ents {:schema good-schema} {:like [[3]]})))
(ex-02)
```

![a happy graph](https://4068685904-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LoN3fu4ydp8osDZFQch%2F-Lp0manTT3RYiCSFHC32%2F-Lp0qJZ4VuPDB5izwoWp%2Fgood-schema.png?alt=media\&token=d8d20222-f3bb-469b-a895-ed0fdbf20aa9)

You could have instead added the `:uniq` constraint to `:post-id`, and it would have generated new `:post`s instead of `:user`s. Give it a try :) Or, try adding the constraint to both `:post-id` and `:created-by-id`.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sweet-tooth.gitbook.io/specmonstah/tutorial/10-uniqueness-constraint.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
