# Mapping Relationships

Mapping a standalone REST endpoint is easy. The tricky part is when the response from a particular endpoint references another endpoint - like foreign keys in a relational database. How can you take advantage of these references in a ng-admin application?

For a simple one-to-many relationship between post and comments, a REST API has three ways to implement the relationship: 
 - using foreign keys,
 - using an array of foreign keys, or
 - using embedded entities.

Ng-admin offers field types for each of these cases. Let's see them in detail.

## Simple Foreign Key

That's the most usual case: the relationship is carried by the `comment` entity, using a `post_id` field referencing a particular `post` entity.

```
GET /posts/456
{
    "id": "456",
    "title": "Consectetur adipisicing elit",
    "body": "Sed do eiusmod..."
}

GET /comments/123
{
    "id": 123,
    "author": "Alice",
    "body": "Lorem ipsum sic dolor amet...",
    "post_id": 456 // foreign key to post of id 456
}
GET /comments/124
{
    "id": 124,
    "author": "Bob",
    "body": "Lorem ipsum sic dolor amet...",
    "post_id": 456 // foreign key to post of id 456
}
```

FKey in comment   | read context      | write context
------------------|-------------------|--------------  
comments for post | `referenced_list` | N/A
post for comment  | `reference`       | `reference`

When displaying a post:

* Use the [`referenced_list` type](reference/Field.md#referenced_list-field-type) to show the comments related to a post in a `showView` or an `editionView`.

        post.showView().fields([
            //...
            nga.field('comments', 'referenced_list') // display list of related comments
                .targetEntity(nga.entity('comments'))
                .targetReferenceField('post_id')
                .targetFields([
                    nga.field('id'),
                    nga.field('created_at').label('Posted'),
                    nga.field('body').label('Comment')
                ])
                .sortField('created_at')
                .sortDir('DESC')
                .listActions(['edit']),

        ])

![referenced_list in showView](images/referenced_list.png)

* Ng-admin doesn't provide the ability to add or remove comments to a post in the post `editionView`. It must be done on the comment `editionView`.

When displaying a comment:

* Use the [`reference` type](reference/Field.md#reference-field-type) to show the post related to a comment in a `listView` or `showView`.

        comment.listView().fields([
            // ...
            nga.field('post_id', 'reference')
                .isDetailLink(false)
                .label('Post')
                .targetEntity(post)
                .targetField(nga.field('title').map(truncate))
                .singleApiCall(ids => ({'id': ids }))
        ])

![reference in listView](images/reference_in_listView.png)

* Use the [`reference` type](reference/Field.md#reference-field-type) to let users choose the related post in a `creationView` or an `editionView`.

        comment.editionView().fields([
            // ...
            nga.field('post_id', 'reference')
                .label('Post')
                .targetEntity(post)
                .targetField(nga.field('title').map(truncate))
                .sortField('title')
                .sortDir('ASC')
                .validation({ required: true })
                .remoteComplete(true, {
                    refreshDelay: 200,
                    searchQuery: search => ({ q: search })
                })
        ])

![reference in editionView](images/reference_in_editionView.png)

## Array Of Foreign Keys

The relationship is sometimes carried by the other side. Let's use a slighlty different example this time: the `post` entity contains a list of `tag` ids referencing a list of `tag` entities:

```
GET /posts/456
{
    "id": "456",
    "title": "Consectetur adipisicing elit",
    "body": "Sed do eiusmod...",
    "tags": [67, 98]
}

GET /tags/67
{
    "id": 67,
    "name": "Sport"
}
GET /tags/98
{
    "id": 98,
    "name": "Photo"
}
```

array of FKeys in post | read context     | write context
-----------------------|------------------|-------------  
tags for post          | `reference_many` | `reference_many`
post for tag           | N/A              | N/A

* Use the [`reference_many` type](reference/Field.md#reference_many-field-type) to show the tags related to a post in a ` listView`, a `showView`, or an `editionView`.

        post.listView().fields([
            // ...
            nga.field('tags', 'reference_many')
                .targetEntity(nga.entity('tag'))
                .targetField(nga.field('name'))
                .singleApiCall(ids => ({'id': ids }))
        ])

![reference_many in listView](images/reference_many_in_listView.png)

* Use the [`reference_many` type](reference/Field.md#reference_many-field-type) to add or remove tags to a post in the post `editionView`.

        post.editionView().fields([
            // ...
            nga.field('tags', 'reference_many')
                .targetEntity(nga.entity('tag'))
                .targetField(nga.field('name'))
                .attributes({ placeholder: 'Select some tags...' })
                .remoteComplete(true, {
                    refreshDelay: 300 ,
                    searchQuery: search => ({ q: search })
                })
        ])

![reference_many in an editionView](images/reference_many_in_editionView.png)

When displaying a tag:

* Ng-admin doesn't provide the ability to show the post related to a tag in a `listView` or `showView`.
* Ng-admin doesn't provide the ability to let the user choose the related post in a `creationView` or an `editionView`.

**Note**: APIs often use arrays of foreign keys to render a many-to-many relationship (the other side of the relationship can also contain an array of foreign keys).

## Embedded Entities

APIs sometimes render a one-to-many relationship by embedding the related entries in the main entry:

```
GET /posts/456
{
    "id": "1",
    "title": "Consectetur adipisicing elit",
    "body": "Sed do eiusmod...",
    "comments": [
        {
            "date": "2014-09-24",
            "body": "Lorem ipsum sic dolor amet...",
        },
        {
            "date": "2012-08-09",
            "body": "Lorem ipsum sic dolor amet...",
        }
    ]
}
```

array of entities in post | read context     | write context
--------------------------|------------------|-------------  
comments for post         | `embedded_list`  | `embedded_list`
post for comment          | N/A              | N/A

When displaying a post:

* Use the [`embedded_list` type](reference/Field.md#embedded_list-field-type) to show the comments related to a post in a `showView`.

        post.showView().fields([
            // ...
            nga.field('comments', 'embedded_list') // Define a 1-N relationship with the (embedded) comment entity
                .targetFields([ // which comment fields to display in the datagrid / form
                    nga.field('date', 'date').label('Posted'),
                    nga.field('body'),
                ]),
            // ...
        ]);

![embedded_list in showView](images/embedded_list_in_showView.png)

* Use the [`embedded_list` type](reference/Field.md#embedded_list-field-type) to add or remove comments to a post in the post `creationView` or `editionView`.

        post.editionView().fields([
            // ...
            nga.field('comments', 'embedded_list') // Define a 1-N relationship with the (embedded) comment entity
                .targetFields([ // which comment fields to display in the datagrid / form
                    nga.field('date', 'date').label('Posted')
                    nga.field('body')
                ])
        ]);

![embedded_list in editionView](images/embedded_list_in_editionView.png)

## Embedded entity

APIs may render a many-to-one relationship by embedding the related entry in the main entry:

```
GET /comments/123
{
    "id": 123,
    "author": "Alice",
    "body": "Lorem ipsum sic dolor amet...",
    "post": {
        "id": "456",
        "title": "Consectetur adipisicing elit",
        "body": "Sed do eiusmod...",
    }
}
```

When displaying a comment, use the dot notation to show the post related to a comment in any view (works in `listView`, `showView`, `creationView`, and `editionView`):

```
comment.listView().fields([
    nga.field('date').label('Posted'),
    nga.field('author'),
    nga.field('body'),
    nga.field('post.title'), // dot notation
])
```

![dot notation in listView](images/dot_notation_in_listView.png)

The inlined post fields renders the same as other comment fields.

entity in comment | read context | write context
------------------|--------------|-------------  
comments for post | dot notation | dot notation
post for comment  | N/A          | N/A
