---
title: LDAP search
description: Examples in this documentation depend on features activated in the ds-evaluation setup profile.
component: pingds
version: 8.1
page_id: pingds:ldap-guide:search-ldap
canonical_url: https://docs.pingidentity.com/pingds/8.1/ldap-guide/search-ldap.html
revdate: 2025-10-22T14:42:39Z
keywords: ["LDAP"]
section_ids:
  simple-filter-search: Simple LDAP filter
  complex-filter-search: Complex LDAP filter
  substring-seaches: Substring searches
  operational-attrs-search: Return operational attributes
  attr-desc-list-search: Return attributes of an object class
  approximate-match-search: Approximate match
  escape-characters-in-filter: Escape characters in filters
  root-dse-search: Read directory capabilities
  extensible-match-search: Active accounts
  localized-search: Language subtypes
  filter-operators: LDAP filter operators
  json-search: JSON query filters
  json-token-search: JSON assertions
  server-side-sort: Server-side sort
  dn-pattern-matching: DN patterns
---

# LDAP search

|   |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| - | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | Examples in this documentation depend on features activated in [the `ds-evaluation` setup profile](../install-guide/setup-ds.html#about-ds-evaluation).The code samples demonstrate how to contact the server over HTTPS using the deployment CA certificate. Before trying the samples, generate the CA certificate in PEM format from the server deployment ID and password:```console
$ dskeymgr \
 export-ca-cert \
 --deploymentId $DEPLOYMENT_ID \
 --deploymentIdPassword password \
 --outputFile ca-cert.pem
``` |

Searching the directory is like searching for a phone number in a paper phone book. You can look up a phone number because you know the last name of a subscriber's entry. In other words, you use the value of one attribute of the entry to find entries that have another attribute you want.

Whereas a phone book has only one index (alphabetical order by name), the directory has many indexes. When performing a search, you specify which attributes to use, and the server derives the corresponding indexes.

The phone book might be divided into white pages for residential subscribers and yellow pages for businesses. If you look up an individual's phone number, you limit your search to the white pages. Directory services divide entries in various ways. For example, they can store organizations and groups in different locations from user entries or printer accounts. When searching the directory, you therefore also specify where to search.

The `ldapsearch` command requires arguments for at least the search base DN option and an LDAP filter. The search base DN identifies where in the directory to search for entries that match the filter. For example, if you are looking for printers, you might use `ou=Printers,dc=example,dc=com`. In the `GNB00` office, you could look up a printer as shown in the following example:

```console
$ ldapsearch --baseDN ou=Printers,dc=example,dc=com "(printerLocation=GNB00)"
```

In the example above, the LDAP filter matches printer entries where the `printerLocation` attribute is equal to `GNB00`.

You also specify the host and port to access directory services, and the protocol to use, such as LDAP or LDAPS. If the directory service does not allow anonymous access to the data you want to search, you supply credentials, such as a username and password, or a public key certificate. You can optionally specify a list of attributes to return. If you do not specify attributes, then the search returns all user attributes for the entry.

For details about the operators that can be used in search filters, refer to [LDAP filter operators](#filter-operators).

## Simple LDAP filter

The following example searches for entries with user IDs (`sn`) equal to `hall`, returning only DNs and user ID values:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN dc=example,dc=com \
 "(sn=hall)" \
 uid
```

> **Collapse: Show output**
>
> ```
> dn: uid=ahall,ou=People,dc=example,dc=com
> uid: ahall
>
> dn: uid=bhal2,ou=People,dc=example,dc=com
> uid: bhal2
>
> dn: uid=bhall,ou=People,dc=example,dc=com
> uid: bhall
> ```

## Complex LDAP filter

The following example returns entries with `sn` equal to `jensen` for users located in San Francisco:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN ou=people,dc=example,dc=com \
 "(&(sn=jensen)(l=San Francisco))" \
 @person
```

> **Collapse: Show output**
>
> ```
> dn: uid=bjensen,ou=People,dc=example,dc=com
> objectClass: person
> objectClass: cos
> objectClass: oauth2TokenObject
> objectClass: inetOrgPerson
> objectClass: organizationalPerson
> objectClass: posixAccount
> objectClass: top
> cn: Barbara Jensen
> cn: Babs Jensen
> description: Original description
> sn: Jensen
> telephoneNumber: +1 408 555 1862
>
> dn: uid=rjensen,ou=People,dc=example,dc=com
> objectClass: person
> objectClass: cos
> objectClass: inetOrgPerson
> objectClass: organizationalPerson
> objectClass: posixAccount
> objectClass: top
> cn: Richard Jensen
> description: Description on ou=People
> sn: Jensen
> telephoneNumber: +1 408 555 5957
> ```

The command returns the attributes associated with the `person` object class.

Complex filters can use both "and" syntax, `(&(filtercomp)(filtercomp))`, and "or" syntax, `(|(filtercomp)(filtercomp))`.

## Substring searches

Sometimes you only have part of the value that the search must match. Use a *substring search* in this case.

The following example returns entries with phone numbers that contain `5551212`:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN ou=people,dc=example,dc=com \
 "(telephoneNumber=*5551212*)"
```

The following example returns entries where the full name (common name) starts with `Barb`:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN ou=people,dc=example,dc=com \
 "(cn=barb*)"
```

The filter has `barb` in lower case because the `cn` attribute is case-insensitive. Many standard LDAP attributes are case-insensitive.

The following example returns entries where the full name ends with `ensen`:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN ou=people,dc=example,dc=com \
 "(sn=*ensen)"
```

|   |                                                                                                                                                                                               |
| - | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | If you had the whole last name, such as `Jensen`, then you would use `(sn=jensen)` as the search filter. Substring searches are useful, but they are also more expensive than exact searches. |

## Return operational attributes

Operational attributes are returned only when explicitly requested. Use `+` in the attribute list after the filter to return all operational attributes:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN dc=example,dc=com \
 "(uid=bjensen)" \
 +
```

> **Collapse: Show output**
>
> ```
> dn: uid=bjensen,ou=People,dc=example,dc=com
> collectiveAttributeSubentries: cn=Bronze Class of Service,dc=example,dc=com
> collectiveAttributeSubentries: cn=Inherit Department Number From Manager,dc=example,dc=com
> collectiveAttributeSubentries: cn=Inherit From Locality,dc=example,dc=com
> collectiveAttributeSubentries: cn=Inherit Description From Parent,dc=example,dc=com
> ds-pwp-state-json: { "require-secure-authentication": true, "password-policy-dn": "cn=Default Password Policy,cn=Password Policies,cn=config", "force-change-on-reset": false, "account-is-expired": false, "account-is-idle-locked": false, "account-is-disabled": false, "account-is-reset-locked": false, "must-change-password": false, "password-is-expired": false, "is-within-minimum-password-age": false, "account-is-usable": true, "require-secure-password-changes": true, "force-change-on-add": false }
> entryDN: uid=bjensen,ou=People,dc=example,dc=com
> entryUUID: <uuid>
> etag: <etag>
> hasSubordinates: false
> isMemberOf: cn=Carpoolers,ou=Self Service,ou=Groups,dc=example,dc=com
> numSubordinates: 0
> pwdPolicySubentry: cn=Default Password Policy,cn=Password Policies,cn=config
> structuralObjectClass: inetOrgPerson
> subschemaSubentry: cn=schema
> ```

Alternatively, specify operational attributes by name.

## Return attributes of an object class

Use `@objectClass` in the attribute list to return all attributes of a particular object class:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN dc=example,dc=com \
 "(uid=bjensen)" \
  @person
```

> **Collapse: Show output**
>
> ```
> dn: uid=bjensen,ou=People,dc=example,dc=com
> objectClass: person
> objectClass: cos
> objectClass: oauth2TokenObject
> objectClass: inetOrgPerson
> objectClass: organizationalPerson
> objectClass: posixAccount
> objectClass: top
> cn: Barbara Jensen
> cn: Babs Jensen
> description: Original description
> sn: Jensen
> telephoneNumber: +1 408 555 1862
> ```

## Approximate match

DS servers support searches for an approximate match of the filter. Approximate match searches use the `~=` comparison operator, described in [LDAP filter operators](#filter-operators). They rely on `approximate` type indexes, which are configured as shown in [Approximate index](../config-guide/idx-config.html#approx-index-example).

The following example configures an approximate match index for the surname (`sn`) attribute, and then rebuilds the index:

```console
$ dsconfig \
 set-backend-index-prop \
 --hostname localhost \
 --port 4444 \
 --bindDN uid=admin \
 --bindPassword password \
 --backend-name dsEvaluation \
 --index-name sn \
 --set index-type:approximate \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --no-prompt
$ rebuild-index \
 --hostname localhost \
 --port 4444 \
 --bindDN uid=admin \
 --bindPassword password \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --baseDN dc=example,dc=com \
 --index sn
```

Once the index is built, it is ready for use in searches. The following example shows a search using the approximate comparison operator:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN dc=example,dc=com \
 "(sn~=jansen)" \
 sn
```

> **Collapse: Show output**
>
> ```
> dn: uid=ajensen,ou=People,dc=example,dc=com
> sn: Jensen
>
> dn: uid=bjense2,ou=People,dc=example,dc=com
> sn: Jensen
>
> dn: uid=bjensen,ou=People,dc=example,dc=com
> sn: Jensen
>
> dn: uid=ejohnson,ou=People,dc=example,dc=com
> sn: Johnson
>
> dn: uid=gjensen,ou=People,dc=example,dc=com
> sn: Jensen
>
> dn: uid=jjensen,ou=People,dc=example,dc=com
> sn: Jensen
>
> dn: uid=kjensen,ou=People,dc=example,dc=com
> sn: Jensen
>
> dn: uid=rjense2,ou=People,dc=example,dc=com
> sn: Jensen
>
> dn: uid=rjensen,ou=People,dc=example,dc=com
> sn: Jensen
>
> dn: uid=tjensen,ou=People,dc=example,dc=com
> sn: Jensen
> ```

Notice that `jansen` matches `Jensen` and `Johnson`.

## Escape characters in filters

[RFC 4515](https://www.rfc-editor.org/info/rfc4515), *Lightweight Directory Access Protocol (LDAP): String Representation of Search Filters*, mentions a number of characters that require special handing in search filters.

For a filter like `(attr=value)`, the following list indicates characters that you must replace with a backslash (`\`) followed by two hexadecimal digits when using them as part of the value string:

* Replace `*` with `\2a`.

* Replace `(` with `\28`.

* Replace `)` with `\29`.

* Replace `\` with `\5c`.

* Replace NUL (0x00) with `\00`.

The following example shows a filter with escaped characters matching an actual value:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN dc=example,dc=com \
 "(cn=\28A \5cgreat\5c name\2a\29)" \
 cn
```

> **Collapse: Show output**
>
> ```
> dn: uid=bjensen,ou=People,dc=example,dc=com
> cn: Barbara Jensen
> cn: Babs Jensen
> cn: (A \great\ name*)
> ```

## Read directory capabilities

The root DSE is a single entry describing server capabilities in operational attributes.

Use `ldapsearch --baseDn "" --searchScope base "(&)" +` to read the operational attributes of the root DSE:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --usePkcs12TrustStore /path/to/opendj/config/keystore \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --baseDN "" \
 --searchScope base \
 "(&)" \
 +
```

## Active accounts

DS servers support extensible matching rules. Use a filter that specifies a matching rule OID that extends the matching operator.

DS servers support time-based matching rules for use with attributes that hold timestamp values:

* Name: `relativeTimeOrderingMatch.gt`

  Greater-than relative time matching rule for time-based searches.

  Use this in a filter to match attributes with values greater than the current time +/- an offset.

  The filter `(pwdExpirationTime:1.3.6.1.4.1.26027.1.4.5:=5d)` matches entries where the password expiration time is greater than the current time plus five days. In other words, entries whose passwords expire in more than five days.

* Name: `relativeTimeOrderingMatch.lt`

  Less-than relative time matching rule for time-based searches.

  Use this in a filter to match attributes with values less than the current time +/- an offset.

  The filter `(ds-last-login-time:1.3.6.1.4.1.26027.1.4.6:=-4w)` matches entries where the last login time is less than the current time minus four weeks. In other words, accounts that have not been active in the last four weeks.

* Name: `partialDateAndTimeMatchingRule`

  Partial date and time matching rule for matching parts of dates in time-based searches.

  The filter `(ds-last-login-time:1.3.6.1.4.1.26027.1.4.7:=2020)` matches entries where the last login time was in 2020.

The following example uses the `ds-last-login-time` attribute, which is an operational attribute (`USAGE directoryOperation`) with [Generalized Time](../schemaref/s-GeneralizedTime.html) syntax (`SYNTAX 1.3.6.1.4.1.1466.115.121.1.24`).

When checking schema compliance, the server skips operational attributes. The server can therefore add operational attributes to an entry without changing the entry's object classes.

Operational attributes hold information for the directory, rather than information targeting client applications. The server returns operational attributes only when explicitly requested, and client applications generally should not be able to modify them.

As the `ds-last-login-time` attribute is operational, it has limited visibility. This helps prevent client applications from modifying its value unless specifically allowed to.

Configure the applicable password policy to write the last login timestamp when a user authenticates.

The following command configures a subentry password policy. On successful authentication, the policy causes the server to write a timestamp in generalized time format to the user's `ds-last-login-time` operational attribute:

```console
$ ldapmodify \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=admin \
 --bindPassword password << EOF
dn: cn=Record last login,dc=example,dc=com
objectClass: top
objectClass: subentry
objectClass: ds-pwp-password-policy
cn: Record last login
ds-pwp-password-attribute: userPassword
ds-pwp-default-password-storage-scheme: PBKDF2-HMAC-SHA256
ds-pwp-last-login-time-attribute: ds-last-login-time
ds-pwp-last-login-time-format: yyyyMMddHH'Z'
subtreeSpecification: { base "ou=people" }
EOF
```

The `ds-pwp-last-login-time-format` setting must:

* Match the syntax of the `ds-pwp-last-login-time-attribute` attribute, which in this example is `GeneralizedTime`.

* Be a valid format string for the `java.text.SimpleDateFormat` class.

With the setting shown in the example, `ds-pwp-last-login-time-format: yyyyMMddHH'Z'`, DS records last login time to the nearest hour. For each bind where the timestamp changes, DS updates the timestamp on the entry. So this recommended setting avoids updating entries often for users who bind repeatedly over a short period. If the deployment requires a fine-grained last login timestamp, use a format that includes minutes or seconds. For example, to get last login times that are accurate to the second, use `ds-pwp-last-login-time-format:"yyyyMMddHHmmss'Z'"`.

Configure and build an index for time-based searches on the `ds-last-login-time` attribute:

```console
$ dsconfig \
 create-backend-index \
 --hostname localhost \
 --port 4444 \
 --bindDN uid=admin \
 --bindPassword password \
 --backend-name dsEvaluation \
 --set index-type:extensible \
 --set index-extensible-matching-rule:1.3.6.1.4.1.26027.1.4.5 \
 --set index-extensible-matching-rule:1.3.6.1.4.1.26027.1.4.6 \
 --set index-extensible-matching-rule:1.3.6.1.4.1.26027.1.4.7 \
 --index-name ds-last-login-time \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --no-prompt
$ rebuild-index \
 --hostname localhost \
 --port 4444 \
 --bindDN uid=admin \
 --bindPassword password \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --baseDN dc=example,dc=com \
 --index ds-last-login-time
```

Make sure you have some users who have authenticated recently:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=bjensen,ou=people,dc=example,dc=com \
 --bindPassword hifalutin \
 --baseDN dc=example,dc=com \
 "(uid=bjensen)" \
 1.1
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=people,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN dc=example,dc=com \
 "(uid=bjensen)" \
 1.1
```

The following search returns users who have authenticated in the last 13 weeks:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=admin \
 --bindPassword password \
 --baseDN dc=example,dc=com \
 "(ds-last-login-time:1.3.6.1.4.1.26027.1.4.5:=-13w)" \
 1.1
```

> **Collapse: Show output**
>
> ```
> dn: uid=bjensen,ou=People,dc=example,dc=com
>
> dn: uid=kvaughan,ou=People,dc=example,dc=com
> ```

The following search returns users who have authenticated this year:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=admin \
 --bindPassword password \
 --baseDN dc=example,dc=com \
 "(ds-last-login-time:1.3.6.1.4.1.26027.1.4.7:=$(date +%Y))" \
 1.1
```

> **Collapse: Show output**
>
> ```
> dn: uid=bjensen,ou=People,dc=example,dc=com
>
> dn: uid=kvaughan,ou=People,dc=example,dc=com
> ```

## Language subtypes

DS servers support the language subtypes listed in [Support for languages and locales](../ldap-reference/l10n.html).

When you perform a search you can request the language subtype by OID or by language subtype string. For example, the following search gets the French version of a common name. The example uses the DS `base64` command to decode the attribute value:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN dc=example,dc=com \
 "(cn=Frederique Dupont)" cn\;lang-fr
```

> **Collapse: Show output**
>
> ```
> dn: uid=fdupont,ou=People,dc=example,dc=com
> cn;lang-fr:: RnJlZMOpcmlxdWUgRHVwb250
> ```

```console
$ base64 decode --encodedData RnJlZMOpcmlxdWUgRHVwb250
```

> **Collapse: Show output**
>
> ```
> Fredérique Dupont
> ```

At the end of the OID or language subtype, further specify the matching rule as follows:

* Add `.1` for less than

* Add `.2` for less than or equal to

* Add `.3` for equal to (default)

* Add `.4` for greater than or equal to

* Add `.5` for greater than

* Add `.6` for substring

## LDAP filter operators

| Operator        | Definition                                                                                                                                                                                                                                                                                                                | Example                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `=`             | Equality comparison, as in `(sn=Jensen)`.This can also be used with substring matches. For example, to match last names starting with `Jen`, use the filter `(sn=Jen*)`. Substrings are more expensive for the directory server to index. Substring searches might not be permitted, depending on the attribute.          | `"(cn=My App)"` matches entries with common name `My App`.`"(sn=Jen*)"` matches entries with surname starting with `Jen`.                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `<=`            | Less than or equal to comparison, which works alphanumerically.                                                                                                                                                                                                                                                           | `"(cn<=App)"` matches entries with `commonName` up to those starting with App (case-insensitive) in alphabetical order.                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `>=`            | Greater than or equal to comparison, which works alphanumerically.                                                                                                                                                                                                                                                        | `"(uidNumber>=1151)"` matches entries with `uidNumber` greater than 1151.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `=*`            | Presence comparison. For example, to match all entries with a `userPassword` attribute, use the filter `(userPassword=*)`.                                                                                                                                                                                                | `"(member=*)"` matches entries with a `member` attribute.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `~=`            | Approximate comparison, matching attribute values similar to the value you specify.                                                                                                                                                                                                                                       | `"(sn~=jansen)"` matches entries with a surname that sounds similar to `Jansen` (Johnson, Jensen, and other surnames).                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `[:dn][:oid]:=` | Extensible match comparison.At the end of the OID or language subtype, you further specify the matching rule as follows:- Add `.1` for less than

- Add `.2` for less than or equal to

- Add `.3` for equal to (default)

- Add `.4` for greater than or equal to

- Add `.5` for greater than

- Add `.6` for substring | `(uid:dn:=bjensen)` matches entries with DN component `uid=bjensen`.`(ds-last-login-time: 1.3.6.1.4.1.26027.1.4.5:=-13w)` matches entries with a last login time more recent than 13 weeks.Extensible match filters work with localized values. DS servers support internationalized locales, each of which has an OID for collation order, such as `1.3.6.1.4.1.42.2.27.9.4.76.1` for French. DS software lets you use the language subtype, such as `fr`, instead of the OID.`"(cn:dn:=My App)"` matches entries with `cn: My App` and DN component `cn=My App`. |
| `!`             | NOT operator, to find entries that do not match the specified filter component.Take care to limit your search when using `!` to avoid matching so many entries that the server treats your search as unindexed.                                                                                                           | `'!(objectclass=person)'` matches non-person entries.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `&`             | AND operator, to find entries that match all specified filter components.                                                                                                                                                                                                                                                 | `'(&(l=San Francisco)(!(uid=bjensen)))'` matches entries for users in San Francisco other than the user with ID `bjensen`.                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `\|`            | OR operator, to find entries that match one of the specified filter components.                                                                                                                                                                                                                                           | `"\|(sn=Jensen)(sn=Johnson)"` matches entries with surname Jensen or surname Johnson.                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |

## JSON query filters

DS servers support attribute values that have JSON syntax. This makes it possible to index JSON values, and to search for them using Common REST query filters, as described in [HDAP API reference](../rest-guide/rest-operations.html).

The following examples depend on settings applied with the `ds-evaluation` setup profile.

The first example uses a custom JSON query index for an `oauth2Token` JSON attribute. The index lets you search with Common REST query filters. The search finds the entry with `"access_token": "123"`:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN dc=example,dc=com \
 "(oauth2Token=access_token eq '123')" \
 oauth2Token
```

> **Collapse: Show output**
>
> ```
> dn: uid=bjensen,ou=People,dc=example,dc=com
> oauth2Token: {"access_token":"123","expires_in":59,"token_type":"Bearer","refresh_token":"456"}
> ```

You can combine Common REST query filter syntax filters with other LDAP search filter to form complex filters, as demonstrated in [Complex LDAP filter](#complex-filter-search). For example, `(&(oauth2Token=access_token eq '123')(mail=bjensen@example.com))`.

The next example relies on a default JSON query index for equality, part of the `ds-evaluation` setup profile. The index applies to a `json` attribute that holds arbitrary JSON objects. The search finds an entry with a `json` attribute that has an "array" field containing an array of objects:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN dc=example,dc=com \
 "(json=array[x eq 1 and y eq 2])" \
 json
```

> **Collapse: Show output**
>
> ```
> dn: uid=abarnes,ou=People,dc=example,dc=com
> json: {"array":[{"x":1,"y":2},{"x":3,"y":4}]}
> ```

Notice the value of the `json` attribute: `{"array":[{"x":1,"y":2},{"x":3,"y":4}]}`:

* The filter `"(json=array[x eq 1 and y eq 2])"` matches because it matches the first object of the array.

* The filter `"(array[x eq 1] and array[y eq 4])"` matches because it matches both objects in the array.

* The filter `"(json=array[x eq 1 and y eq 4])"` fails to match, because the array has no object `{"x":1,"y":4}`.

## JSON assertions

In addition to searches with query filters, JSON attributes can be matched with filters using JSON in the assertion. This example demonstrates a case where JSON objects are considered equal if their "id" fields match. This example depends on settings applied with the `ds-evaluation` setup profile.

Search for entries with a `jsonToken` attribute:

```console
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDN dc=example,dc=com \
 '(jsonToken={"id":"HgAaB6xDhLom4JbM"})' \
 jsonToken
```

> **Collapse: Show output**
>
> ```
> jsonToken: {"id":"HgAaB6xDhLom4JbM","scopes":["read","write"],"expires":"2018-01-10T10:08:34Z"}
> ```

## Server-side sort

If permitted by the directory administrator, you can request that the server sort the search results. When your application requests a server-side sort, the server retrieves the entries matching your search, and then returns the whole set of entries in sorted order.

The following example grants access to use the server-side sort control:

> **Collapse: Show example**
>
> ```console
> $ ldapmodify \
>  --hostname localhost \
>  --port 1636 \
>  --useSsl \
>  --trustStorePath /path/to/opendj/config/keystore \
>  --trustStoreType PKCS12 \
>  --trustStorePassword:file /path/to/opendj/config/keystore.pin \
>  --bindDn uid=admin \
>  --bindPassword password << EOF
> dn: dc=example,dc=com
> changetype: modify
> add: aci
> aci: (targetcontrol = "ServerSideSort")
>  (version 3.0;acl "Allow Server-Side Sort for Kirsten Vaughan";
>  allow (read)(userdn = "ldap:///uid=kvaughan,ou=People,dc=example,dc=com");)
> EOF
> ```

This process consumes memory resources on the server, so the best practice is to sort results on the client side, or to browse results with a search that matches a virtual list view index, as demonstrated in [Virtual list view index](../config-guide/idx-config.html#configure-vlv).

DS supports the following sort key forms. The `ldapsearch` command `--sortOrder` option takes these forms as arguments:

* `[+|-]attr`

  Use this form with standard LDAP attributes.

  The optional plus or minus sign defines the order, and *attr* is the name of the LDAP attribute to sort on.

  For example, `cn` and `+cn` sort by common name in ascending order. `-sn` sorts by surname in descending order.

  The following example sorts the results in ascending order by surname using `--sortOrder +sn`:

  > **Collapse: Show example**
  >
  > ```console
  > $ ldapsearch \
  >  --hostname localhost \
  >  --port 1636 \
  >  --useSsl \
  >  --trustStorePath /path/to/opendj/config/keystore \
  >  --trustStoreType PKCS12 \
  >  --trustStorePassword:file /path/to/opendj/config/keystore.pin \
  >  --bindDn uid=kvaughan,ou=people,dc=example,dc=com \
  >  --bindPassword bribery \
  >  --baseDn dc=example,dc=com \
  >  --sortOrder +sn \
  >  "(&(sn=*)(cn=babs*))" \
  >  cn
  > ```
  >
  > Output
  >
  > ```
  > dn: uid=user.94643,ou=People,dc=example,dc=com
  > cn: Babs Bautista
  >
  > dn: uid=user.81225,ou=People,dc=example,dc=com
  > cn: Babs Bawek
  >
  > dn: uid=user.67807,ou=People,dc=example,dc=com
  > cn: Babs Baxter
  >
  > dn: uid=user.54389,ou=People,dc=example,dc=com
  > cn: Babs Bayer
  >
  > dn: uid=user.40971,ou=People,dc=example,dc=com
  > cn: Babs Bayerkohler
  >
  > dn: uid=user.27553,ou=People,dc=example,dc=com
  > cn: Babs Bayless
  >
  > dn: uid=user.14135,ou=People,dc=example,dc=com
  > cn: Babs Bayley
  >
  > dn: uid=user.717,ou=People,dc=example,dc=com
  > cn: Babs Bayly
  >
  > dn: uid=bjensen,ou=People,dc=example,dc=com
  > cn: Barbara Jensen
  > cn: Babs Jensen
  >
  > dn: uid=user.89830,ou=People,dc=example,dc=com
  > cn: Babs Pdesupport
  >
  > dn: uid=user.76412,ou=People,dc=example,dc=com
  > cn: Babs Peacemaker
  >
  > dn: uid=user.62994,ou=People,dc=example,dc=com
  > cn: Babs Peacocke
  >
  > dn: uid=user.49576,ou=People,dc=example,dc=com
  > cn: Babs Peake
  >
  > dn: uid=user.36158,ou=People,dc=example,dc=com
  > cn: Babs Pearce
  >
  > dn: uid=user.22740,ou=People,dc=example,dc=com
  > cn: Babs Pearcy
  >
  > dn: uid=user.9322,ou=People,dc=example,dc=com
  > cn: Babs Pearse
  > ```

* `[+|-]jsonAttr:customJsonOrderingMatchingRule`

  Use this form to sort on predefined fields in LDAP attributes whose values are JSON objects.

  Here, *jsonAttr* is the attribute name of the JSON attribute, and *customJsonOrderingMatchingRule* is one defined in the LDAP schema and backed by a custom schema provider. For details, refer to [Schema and JSON](../config-guide/schema.html#json-in-ldap).

  The following example sorts the results in ascending order by the "id" field of the `jsonToken` attribute. The custom matching rule, `caseIgnoreJsonTokenIDMatch`, is defined by the `ds-evaluation` setup profile:

  > **Collapse: Show example**
  >
  > ```console
  > $ ldapsearch \
  >  --hostname localhost \
  >  --port 1636 \
  >  --useSsl \
  >  --trustStorePath /path/to/opendj/config/keystore \
  >  --trustStoreType PKCS12 \
  >  --trustStorePassword:file /path/to/opendj/config/keystore.pin \
  >  --bindDn uid=kvaughan,ou=people,dc=example,dc=com \
  >  --bindPassword bribery \
  >  --baseDn dc=example,dc=com \
  >  --sortOrder +jsonToken:caseIgnoreJsonTokenIDMatch \
  >  "(objectClass=jsonTokenObject)" \
  >  jsonToken
  > ```
  >
  > Output
  >
  > ```
  > dn: uid=mjablons,ou=People,dc=example,dc=com
  > jsonToken: {"id":"HgAaB6xDhLom4JbM","scopes":["read","write"],"expires":"2018-01-10T10:08:34Z"}
  >
  > dn: uid=awhite,ou=People,dc=example,dc=com
  > jsonToken: {"id":"HkV5KzDrOgqN4prp","scopes":["read"],"expires":"2018-01-10T11:09:12Z"}
  > ```

* `[+|-]jsonAttr:extensibleJsonOrderingMatch:caseSensitive?:ignoreSpace?:/jsonPath[:/jsonPath…​]`

  Use this form to sort on arbitrary fields in LDAP attributes whose values are JSON objects.

  DS creates a matching rule on demand, if necessary. In that case, the search is unindexed.

  The following example uses this sort key form to mimic the previous example that used a custom JSON ordering rule:

  > **Collapse: Show example**
  >
  > ```console
  > $ ldapsearch \
  >  --hostname localhost \
  >  --port 1636 \
  >  --useSsl \
  >  --trustStorePath /path/to/opendj/config/keystore \
  >  --trustStoreType PKCS12 \
  >  --trustStorePassword:file /path/to/opendj/config/keystore.pin \
  >  --bindDn uid=kvaughan,ou=people,dc=example,dc=com \
  >  --bindPassword bribery \
  >  --baseDn dc=example,dc=com \
  >  --sortOrder +jsonToken:extensibleJsonOrderingMatch:true:true:/id \
  >  "(objectClass=jsonTokenObject)" \
  >  jsonToken
  > ```
  >
  > Output
  >
  > ```
  > dn: uid=mjablons,ou=People,dc=example,dc=com
  > jsonToken: {"id":"HgAaB6xDhLom4JbM","scopes":["read","write"],"expires":"2018-01-10T10:08:34Z"}
  >
  > dn: uid=awhite,ou=People,dc=example,dc=com
  > jsonToken: {"id":"HkV5KzDrOgqN4prp","scopes":["read"],"expires":"2018-01-10T11:09:12Z"}
  > ```

  This form has these required parameters:

  * Start with `extensibleJsonOrderingMatch`, or the OID `1.3.6.1.4.1.36733.2.1.4.6`.

  * Set *caseSensitive?* to `true` to respect case when comparing values, `false` otherwise.

  * Set *ignoreSpace?* to `true` to ignore whitespace when comparing values, `false` otherwise.

  * Each */jsonPath* specifies a field inside the JSON object. Specify at least one */jsonPath*.

## DN patterns

LDAP attributes such as `manager` have DN values. After adding an extensible match index for these attributes, you can use wildcards to find matches for specific RDNs in the DN, for example.

The following example demonstrates adding an index, so you can search for Torrey Rigden's (`uid=trigden`) employees, regardless of which company Torrey works for now.

The example that follows creates an extensible match index using the DN pattern matching rule, `distinguishedNamePatternMatch`, which has numeric OID `1.3.6.1.4.1.36733.2.1.4.13`. This supports searches that include wildcards.

The example also indexes `manager` for equality for search filters. The equality index is not required, but can be useful for searches the match entire DNs.

These commands create and rebuild the new index, then search for Torrey Ridgden's employees:

```console
$ dsconfig \
 create-backend-index \
 --backend-name dsEvaluation \
 --index-name manager \
 --set index-extensible-matching-rule:1.3.6.1.4.1.36733.2.1.4.13 \
 --set index-type:equality \
 --set index-type:extensible \
 --type generic \
 --hostname localhost \
 --port 4444 \
 --bindDN uid=admin \
 --bindPassword password \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --no-prompt
$ rebuild-index \
 --index manager \
 --baseDn dc=example,dc=com \
 --hostname localhost \
 --port 4444 \
 --bindDN uid=admin \
 --bindPassword password \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --no-prompt
$ ldapsearch \
 --hostname localhost \
 --port 1636 \
 --useSsl \
 --trustStorePath /path/to/opendj/config/keystore \
 --trustStoreType PKCS12 \
 --trustStorePassword:file /path/to/opendj/config/keystore.pin \
 --bindDN uid=kvaughan,ou=People,dc=example,dc=com \
 --bindPassword bribery \
 --baseDn dc=example,dc=com \
 "(manager:distinguishedNamePatternMatch:=uid=trigden,**)" \
 manager
```

> **Collapse: Show output**
>
> ```
> dn: uid=bjensen,ou=People,dc=example,dc=com
> manager: uid=trigden, ou=People, dc=example,dc=com
> ...
> ```

Notice the search filter, `(manager:distinguishedNamePatternMatch:=uid=trigden,**)`. In DN pattern matching filters:

* `*` matches a single RDN component, or a single RDN component value.

* `**` matches multiple RDN components, or a single RDN component value.

* `+` is the separator for multiple AVAs *(tooltip: \<div class="paragraph">
  \<p>An attribute description and a matching rule assertion value for the attribute used to determine whether an entry matches the assertion.\</p>
  \</div>)* in the same RDN component, as in `sn=smith+givenName=jane,ou=people,dc=example,dc=com`, which matches `sn=*+givenName=*,ou=people,dc=example,dc=com`, for example.

For details, refer to [distinguishedNamePatternMatch](../schemaref/mr-distinguishedNamePatternMatch.html).
