# 11: collection constraint (vector of foreign keys)

Let's say the forum you're building stores a user's favorite posts as a vector of foreign keys, like this:

```scheme
{:username "birb"
 :favorite-ids [1 2 3 4]}
```

Here's how you'd model this in Specmonstah:

```scheme
(ns reifyhealth.specmonstah-tutorial.11
  (:require [clojure.spec.alpha :as s]
            [reifyhealth.specmonstah.core :as sm]
            [reifyhealth.specmonstah.spec-gen :as sg]))

(s/def ::id (s/and pos-int? #(< % 100)))

(s/def ::post (s/keys :req-un [::id]))

(s/def ::favorite-ids (s/coll-of ::id))
(s/def ::user (s/keys :req-un [::id ::favorite-ids]))

(def schema
  {:post {:prefix :p
          :spec   ::post}
   :user {:prefix      :u
          :spec        ::user
          :relations   {:favorite-ids [:post :id]}
          :constraints {:favorite-ids #{:coll}}}})
```

There's our buddy `:constraints` again :) This time the constraint is `:coll`. This is used by the clojure.spec visitor to generate data correctly:

```scheme
(defn ex-01
  []
  (sg/ent-db-spec-gen-attr {:schema schema} {:user [[1]]}))

(ex-01) ;; =>
{:p0 {:id 6}
 :u0 {:id 9, :favorite-ids [6]}}
```

Specmonstah generated a post with `:id` 6, and sure enough you can see that the value of `:favorite-ids` is a vector containing the post's `:id`. But what if you want to generate multiple posts? Here's how you'd do that:

```scheme
(defn ex-02
  []
  (sg/ent-db-spec-gen-attr {:schema schema}
                           {:user [[1 {:refs {:favorite-ids 3}}]]}))
(ex-02)
;; =>
{:p0 {:id 6}
 :p1 {:id 21}
 :p2 {:id 8}
 :u0 {:id 1
      :favorite-ids [6 21 8]}}
```

And boom goes the dynamite. The key here is the map `{:refs {:favorite-ids 3}}` - this tells Specmonstah that this user will have 3 `:favorite-ids`.

You might be wondering, what happens if you generate 2 separate users, each with 3 `:favorite-ids`? Well my friend, wonder no more:

```scheme
(defn ex-03
  []
  (sm/view (sm/add-ents {:schema schema}
                        {:user [[2 {:refs {:favorite-ids 3}}]]})))
(ex-03)
```

![](https://4068685904-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LoN3fu4ydp8osDZFQch%2F-Lp0t0GyLtZlQPEFJXUI%2F-Lp0y6ObnD4JNMm0PXhl%2Fmulti-coll.png?alt=media\&token=71fec078-416a-457b-b97c-3649ed0374ba)

Both users reference the same posts because Specmonstah generates the minimum data necessary to satisfy the query. You can also "manually" specify the ents you want to reference:

```scheme
(defn ex-04
  []
  (sm/view (sm/add-ents {:schema schema}
                        {:user [[1 {:refs {:favorite-ids [:my-p0 :my-p1]}}]
                                [1 {:refs {:favorite-ids [:my-p2 :my-p3]}}]]})))
(ex-04)
```

![](https://4068685904-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LoN3fu4ydp8osDZFQch%2F-Lp0t0GyLtZlQPEFJXUI%2F-Lp0z1FiYQb91oEEjdna%2Fmulti-coll-custom.png?alt=media\&token=c9388801-8865-47f6-8df7-51172df88fee)
