---
title: Mappings with a DS repository
description: For both generic and explicit mappings, IDM maps object types using a dnTemplate property. The dnTemplate is effectively a pointer to where the object is stored in DS. For example, the following excerpt of the default repo.ds.json file shows how configuration objects are stored under the DN ou=config,dc=openidm,dc=forgerock,dc=com:
component: pingidm
version: 8.1
page_id: pingidm:objects-guide:explicit-generic-mapping-ds
canonical_url: https://docs.pingidentity.com/pingidm/8.1/objects-guide/explicit-generic-mapping-ds.html
keywords: ["Data Object Model", "Repository", "Directory Server"]
section_ids:
  generic-mappings-ds: Generic mappings (DS)
  explicit-mappings-ds: Explicit mappings (DS)
  ldap-naming-strategy: Specify how IDM IDs map to LDAP entry names
  relationship-properties-ds: Relationship properties in a DS repository
---

# Mappings with a DS repository

For both generic and explicit mappings, IDM maps object types using a `dnTemplate` property. The `dnTemplate` is effectively a pointer to where the object is stored in DS. For example, the following excerpt of the default `repo.ds.json` file shows how configuration objects are stored under the DN `ou=config,dc=openidm,dc=forgerock,dc=com`:

```json
"config": {
    "dnTemplate": "ou=config,dc=openidm,dc=forgerock,dc=com"
}
```

## Generic mappings (DS)

By default, IDM uses a generic mapping for all objects *except* the following:

* Internal users, roles, and privileges

* Links

* Clustered reconciliation target IDs

  |   |                                                                 |
  | - | --------------------------------------------------------------- |
  |   | Clustered reconciliation is not supported with a DS repository. |

* Locks

* Objects related to queued synchronization

With a generic mapping, all the properties of an object are stored as a single JSON blob in the `fr-idm-json` attribute. To create a new generic mapping, you need only specify the `dnTemplate`; that is, where the object will be stored in the directory tree.

You can specify a wildcard mapping, that stores all nested URIs under a particular branch of the directory tree, for example:

```json
"managed/*": {
    "dnTemplate": "ou=managed,dc=openidm,dc=forgerock,dc=com"
}
```

With this mapping, all objects under `managed/`, such as `managed/user` and `managed/device`, will be stored in the branch `ou=managed,dc=openidm,dc=forgerock,dc=com`. You do not have to specify separate mappings for each of these objects. The mapping creates a new `ou` for each object. So, for example, `managed/user` objects will be stored under the DN `ou=user,ou=managed,dc=openidm,dc=forgerock,dc=com` and `managed/device` objects will be stored under the DN `ou=device,ou=managed,dc=openidm,dc=forgerock,dc=com`.

In cases where you want to improve external DS search performance, you can configure indexing for your resources within DS. For more information on indexing in DS, refer to [Indexes](https://docs.pingidentity.com/pingds/8.1/config-guide/indexing.html) in the DS documentation.

## Explicit mappings (DS)

The default configuration uses a generic mapping for managed user objects. To use an explicit mapping for managed user objects, change the repository configuration *before you start IDM for the first time*.

To set up an explicit mapping:

1. Copy `/path/to/openidm/db/ds/conf/repo.ds-explicit-managed-user.json` to your project's `conf` directory, and rename it `repo.ds.json`:

   ```
   cp /path/to/openidm/db/ds/conf/repo.ds-explicit-managed-user.json project-dir/conf/repo.ds.json
   ```

2. Change the value of the `embedded` property to `false` and add the following properties:

   ```json
   {
     "embedded": false,
     ...
     "security": {
       "trustManager": "file",
       "fileBasedTrustManagerType": "JKS",
       "fileBasedTrustManagerFile": "&{idm.install.dir}/security/truststore",
       "fileBasedTrustManagerPasswordFile": "&{idm.install.dir}/security/storepass"
     },
     "ldapConnectionFactories": {
       "bind": {
         "connectionSecurity": "startTLS",
         "heartBeatIntervalSeconds": 60,
         "heartBeatTimeoutMilliSeconds": 10000,
         "primaryLdapServers": [
           {
             "hostname": "localhost",
             "port": 31389
           }
         ],
         "secondaryLdapServers": []
       },
       "root": {
         "inheritFrom": "bind",
         "authentication": {
           "simple": {
             "bindDn": "uid=admin",
             "bindPassword": "password"
           }
         }
       }
     }
   }
   ```

   Learn more about these properties in [DS Repository Configuration](repo-config.html#repo-ds-json).

3. Start IDM.

IDM uses the DS REST to LDAP gateway to map JSON objects to LDAP objects stored in the directory. To create additional explicit mappings, you must specify the LDAP `objectClasses` to which the object is mapped, and how each property maps to its corresponding LDAP attributes. Specify at least the property `type` and the corresponding `ldapAttribute`. For relationships between objects, you must explicitly define those objects in the repository configuration.

The following excerpt shows an example of an explicit managed user object mapping:

```json
"managed/user" : {
    "dnTemplate": "ou=user,ou=managed,dc=openidm,dc=forgerock,dc=com",
    "objectClasses": [
        "person",
        "organizationalPerson",
        "inetOrgPerson",
        "fr-idm-managed-user-explicit",
        "inetuser"
    ],
    "properties": {
        "_id": {
            "type": "simple", "ldapAttribute": "uid", "isRequired": true, "writability": "createOnly"
        },
        "userName": {
            "type": "simple", "ldapAttribute": "cn"
        },
        "password": {
            "type": "json", "ldapAttribute": "fr-idm-password"
        },
        "accountStatus": {
            "type": "simple", "ldapAttribute": "fr-idm-accountStatus"
        },
        "roles": {
            "type": "json", "ldapAttribute": "fr-idm-role", "isMultiValued": true
        },
        "effectiveRoles": {
            "type": "json", "ldapAttribute": "fr-idm-effectiveRole", "isMultiValued": true
        },
        "effectiveAssignments": {
            "type": "json", "ldapAttribute": "fr-idm-effectiveAssignment", "isMultiValued": true
        },
        ...
    }
}
```

You do not need to map the `_rev` (revision) property of an object as this property is implicit in all objects and maps to the DS `etag` operational attribute.

If your data objects include *virtual properties*, you must include property mappings for these properties. If you don't explicitly map the virtual properties, you will encounter errors similar to the following when you attempt to create the corresponding object:

```json
{
    "code": 400,
    "reason": "Bad Request",
    "message": "Unmapped fields..."
}
```

Learn more about the [REST to LDAP property mappings](https://docs.pingidentity.com/pingds/7.3/rest-guide/rest2ldap.html#mappings-json).

For performance reasons, the DS repository does not apply unique constraints to links. This behavior is different to the JDBC repositories, where uniqueness on link objects is enforced.

|   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|   | DS currently has a default index entry limit of 4000. Therefore, you cannot query more than 4000 records unless you create a Virtual List View (VLV) index. A VLV index is designed to help DS respond to client applications that need to browse through a long list of objects.You cannot create a VLV index on a JSON attribute. For generic mappings, IDM avoids this restriction by using client-side sorting and searching. However, for explicit mappings you *must* create a VLV index for any filtered or sorted results, such as results displayed in a UI grid. To configure a VLV index, use the `dsconfig` command described in [Virtual List View Index](https://docs.pingidentity.com/pingds/8.1/config-guide/indexing.html#configure-vlv) in the *DS Configuration Guide*. |

### Specify how IDM IDs map to LDAP entry names

The DS REST2LDAP configuration lets you set a `namingStrategy` that specifies how LDAP entry names are mapped to JSON resources. When IDM stores its objects in a DS repository, this `namingStrategy` determines how the IDM `_id` value maps to the Relative Distinguished Name (RDN) of the corresponding DS object.

The `namingStrategy` is specified as part of the `explicitMapping` of an object in the `repo.ds.json` file. The following example shows a naming strategy configuration for an explicit managed user mapping:

```json
"resourceMapping": {
    "defaultMapping": {
        "dnTemplate": "ou=generic,dc=openidm,dc=forgerock,dc=com"
    },
    ...
    "explicitMapping": {
        "managed/user": {
            "dnTemplate": "ou=user,ou=managed,dc=openidm,dc=forgerock,dc=com",
            "objectClasses": [
                "person",
                "organizationalPerson",
                "inetOrgPerson",
                "fr-idm-managed-user-explicit"
            ],
            "namingStrategy": {
                "type": "clientDnNaming",
                "dnAttribute": "uid"
            },
            ...
        }
    }
}
```

The `namingStrategy` can be one of the following:

* `clientDnNaming` - IDM provides an `_id` to DS and that `_id` is used to generate the DS RDN. In the following example, the IDM `_id` maps to the LDAP `uid` attribute:

  ```json
  {
      "namingStrategy": {
          "type": "clientDnNaming",
          "dnAttribute": "uid"
      }
  }
  ```

  With this *default* configuration, entries are stored in DS with a DN similar to the following:

  ```none
  "uid=idm-uuid,ou=user,ou=managed,dc=openidm,dc=forgerock,dc=com"
  ```

  |   |                                                                                                                              |
  | - | ---------------------------------------------------------------------------------------------------------------------------- |
  |   | If these default DNs are suitable in your deployment, you do not have to change anything with regard to the naming strategy. |

* `clientNaming` - IDM provides an `_id` to DS but the DS RDN is derived from a different user attribute in the LDAP entry. In the following example, the RDN is the `cn` attribute. The `_id` that IDM provides for the object maps to the LDAP `uid` attribute:

  ```json
  {
      "namingStrategy": {
          "type": "clientNaming",
          "dnAttribute": "cn",
          "idAttribute": "uid"
      }
  }
  ```

  With this configuration, entries are stored in DS with a DN similar to the following:

  ```none
  "cn=username,ou=user,ou=managed,dc=openidm,dc=forgerock,dc=com"
  ```

Specifying a `namingStrategy` is optional. If you do not specify a strategy, the default is `clientDnNaming` with the following configuration:

```json
{
    "namingStrategy" : {
        "type" : "clientDnNaming",
        "dnAttribute" : "uid"
    },
    "properties: : {
        "_id": {
            "type": "simple",
            "ldapAttribute": "uid",
            "isRequired": true,
            "writability": "createOnly"
        },
        ...
    }
}
```

|   |                                                                                                                                                                        |
| - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | If you do not set a `dnAttribute` as part of the naming strategy, the value of the `dnAttribute` is taken from the value of the `ldapAttribute` on the `_id` property. |

## Relationship properties in a DS repository

The IDM object model lets you define [relationships between objects](relationships.html). In a DS repository, relationships are implemented using the `reference` and `reverseReference` REST to LDAP property types. Learn more about the [`reference` and `reverseReference` property types](https://docs.pingidentity.com/pingds/7.3/rest-guide/rest2ldap.html#mappings-json).

Relationship properties must be defined in the repository configuration (`repo.ds.json`), for both generic and explicit object mappings.

The following property definitions for a `managed/user` object show how the relationship between a `manager` and their `reports` is defined in the repository configuration:

```json
"managed/user" : {
    "dnTemplate" : "ou=user,ou=managed,dc=openidm,dc=forgerock,dc=com",
    ...
    "properties" : {
        ...
        "reports" : {
            "type" : "reverseReference",
            "resourcePath" : "managed/user",
            "propertyName" : "manager",
            "isMultiValued" : true
        },
        "manager" : {
            "type" : "reference",
            "ldapAttribute" : "fr-idm-managed-user-manager",
            "primaryKey" : "uid",
            "resourcePath" : "managed/user",
            "isMultiValued" : false
        },
        ...
    }
}
```

This configuration sets the `reports` property as a `reverseReference`, or reverse *relationship* of the `manager` property. This means that if you add a `manager` to a user, the user automatically becomes one of the `reports` of that manager.

Note the `ldapAttribute` defined in the relationship object (`fr-idm-managed-user-manager` in this case). Your DS schema must include this attribute, and an object class that contains this attribute. Relationship attributes in the DS schema must use the [Name and JSON with id](https://docs.pingidentity.com/pingds/8.1/schemaref/s-NameandJSONwithid.html) syntax.

The following example shows the DS schema definition for the IDM `manager` property:

```ldif
attributeTypes: ( 1.3.6.1.4.1.36733.2.3.1.69
  NAME 'fr-idm-managed-user-manager'
  DESC 'Reference to a users manager'
  SINGLE-VALUE
  SYNTAX 1.3.6.1.4.1.36733.2.1.3.12
  EQUALITY nameAndOptionalCaseIgnoreJsonIdEqualityMatch
  X-STABILITY 'Internal' )
```

|   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|   | If you define a relationship in the managed object configuration *(tooltip: You can edit the managed object configuration over REST at the config/managed endpoint, or directly in the conf/managed.json file.)* and you do not define that relationship as a reference or reverse reference in the repository configuration (`repo.ds.json` ), you will be able to query the relationships, but filtering and sorting on those queries will not work. This is the case when you define relationship objects in the admin UI—the relationship is defined only in the managed object configuration and not in the repository configuration.In this case, queries such as the following are not supported:```
curl \
--header "X-OpenIDM-Username: openidm-admin" \
--header "X-OpenIDM-Password: openidm-admin" \
--header "Accept-API-Version: resource=1.0" \
--request GET \
"http://localhost:8080/openidm/managed/user/_id/managedOrgs?_pageSize=50&_sortKeys=_id&_totalPagedResultsPolicy=ESTIMATE&_queryFilter=true"
```This restriction includes delegated admin privilege filters. |
