Search and pagination

Searching is one of the most common LDAP operations. It allows clients to retrieve directory entries matching specific criteria, optionally returning only selected attributes. This section demonstrates a variety of search techniques and server-side features for controlling result sets.

The examples below cover:

  • Basic searches – retrieving entries and attributes within a specified subtree or scope.

  • Iterative searches – streaming results as they arrive.

  • Specialized searches – retrieving only the distinguished names, single attributes, or asserting result uniqueness.

  • Pagination – splitting large result sets into manageable chunks using either the Simple Paged Results control or the Virtual List View control.

  • Sorting – requesting server-side ordering of results.

  • Existence checks – quickly verifying whether an entry exists.

  • Error handling – dealing with missing search bases or other exceptional conditions.

These techniques can be combined to efficiently retrieve exactly the data you need from large or complex directory structures.

Search and receive objects and attributes

subtree search
search_base = 'dc=freeiam,dc=org'

# search for DN and attrs
for entry in await conn.search(
    search_base, Scope.SUBTREE, '(&(uid=*)(objectClass=person))'
):
    print(entry.dn, entry.attr)

Search iterative

iterative search
# search iterative for DN and attrs
async for entry in conn.search_iter(
    search_base, Scope.SUBTREE, '(&(uid=*)(objectClass=person))'
):
    print(entry.dn, entry.attr)

Search for DN only

search for DN
# search for DN
async for entry in conn.search_dn(
    search_base, Scope.SUBTREE, '(&(uid=*)(objectClass=person))'
):
    print(entry.dn)

Paginated search using SimplePagedResult

simple paginated search
# search paginated via SimplePagedResult
async for entry in conn.search_paged(
    search_base,
    Scope.Subtree,
    '(&(uid=*)(objectClass=person))',
    page_size=10,
):
    print(entry.dn, entry.attr, entry.page)

Paginated search using Virtual List View

paginated search
# search paginated via VirtualListView + ServerSideSorting
async for entry in conn.search_paginated(
    search_base,
    Scope.Subtree,
    '(&(uid=*)(objectClass=person))',
    page_size=10,
    sorting=[('uid', 'caseIgnoreOrderingMatch', False)],
):
    print(entry.dn, entry.attr, entry.page)

Get single object

get object
# get a certain object, and use its attributes
obj = await conn.get('uid=max.mustermann,dc=freeiam,dc=org')
print(obj.dn, obj.attr)
print(obj.attr['cn'])
print(obj.attr['CN'])  # yes, attribute names are case sensitive!
print(obj.attr['commonName'])  # and there are even aliases!!!

Get single attribute of certain object

get attribute
# get a attribute of an object (even by alias!)
cn = await conn.get_attr('uid=max.mustermann,dc=freeiam,dc=org', 'commonName')
print(cn)

Search for unique results

assert uniqueness search
# find unique entry
try:
    (_entry,) = await conn.search(
        search_base,
        Scope.SUBTREE,
        '(&(uid=max.mustermann)(objectClass=person))',
        unique=True,
    )
    ...  # do something, ensured to be only the unique entry
except errors.NotUnique as exc:
    # otherwise we have this error here, containg all search results
    print('Bad member in', exc.results)

Check for entry existance

Check if entry exists
# or if you just need to know whether a object exists
await conn.exists('uid=max.mustermann,dc=freeiam,dc=org')

Error handling

Error handling for not existing search bases
# don't forget to handle errors for not existing objects
try:
    await conn.get('uid=max.mustermann,dc=freeiam,dc=org')
except errors.NoSuchObject as exc:
    print(exc.description)