'Recursively finds all db references to be dereferenced
:param items: The iterable (dict, list, queryset)
:param depth: The current depth of recursion
:param instance: The owning instance used for tracking changes by
:class:`~mongoengine.base.ComplexBaseField`
:param name: The name of the field, used for tracking changes by
:class:`~mongoengine.base.ComplexBaseField`'

def _attach_objects(self, items, depth=0, instance=None, name=None):

    if (not items):
        if isinstance(items, (BaseDict, BaseList)):
            return items
        if instance:
            if isinstance(items, dict):
                return BaseDict(items, instance, name)
            else:
                return BaseList(items, instance, name)
    if isinstance(items, (dict, SON)):
        if ('_ref' in items):
            return self.object_map.get((items['_ref'].collection, items['_ref'].id), items)
        elif ('_cls' in items):
            doc = get_document(items['_cls'])._from_son(items)
            _cls = doc._data.pop('_cls', None)
            del items['_cls']
            doc._data = self._attach_objects(doc._data, depth, doc, None)
            if (_cls is not None):
                doc._data['_cls'] = _cls
            return doc
    if (not hasattr(items, 'items')):
        is_list = True
        list_type = BaseList
        if isinstance(items, EmbeddedDocumentList):
            list_type = EmbeddedDocumentList
        as_tuple = isinstance(items, tuple)
        iterator = enumerate(items)
        data = []
    else:
        is_list = False
        iterator = items.iteritems()
        data = {}
    depth += 1
    for (k, v) in iterator:
        if is_list:
            data.append(v)
        else:
            data[k] = v
        if ((k in self.object_map) and (not is_list)):
            data[k] = self.object_map[k]
        elif isinstance(v, (Document, EmbeddedDocument)):
            for field_name in v._fields:
                v = data[k]._data.get(field_name, None)
                if isinstance(v, DBRef):
                    data[k]._data[field_name] = self.object_map.get((v.collection, v.id), v)
                elif (isinstance(v, (dict, SON)) and ('_ref' in v)):
                    data[k]._data[field_name] = self.object_map.get((v['_ref'].collection, v['_ref'].id), v)
                elif (isinstance(v, (dict, list, tuple)) and (depth <= self.max_depth)):
                    item_name = six.text_type('{0}.{1}.{2}').format(name, k, field_name)
                    data[k]._data[field_name] = self._attach_objects(v, depth, instance=instance, name=item_name)
        elif (isinstance(v, (dict, list, tuple)) and (depth <= self.max_depth)):
            item_name = (('%s.%s' % (name, k)) if name else name)
            data[k] = self._attach_objects(v, (depth - 1), instance=instance, name=item_name)
        elif hasattr(v, 'id'):
            data[k] = self.object_map.get((v.collection, v.id), v)
    if (instance and name):
        if is_list:
            return (tuple(data) if as_tuple else list_type(data, instance, name))
        return BaseDict(data, instance, name)
    depth += 1
    return data
