public function documents(array $options = [])
    {
        $maxRetries = $this->pluck('maxRetries', $options, false);
        $maxRetries = $maxRetries === null
            ? FirestoreClient::MAX_RETRIES
            : $maxRetries;

        $rows = (new ExponentialBackoff($maxRetries))->execute(function () use ($options) {
            $query = $this->finalQueryPrepare($this->query);
            $generator = $this->connection->runQuery($this->arrayFilterRemoveNull([
                'parent' => $this->parent,
                'structuredQuery' => $query,
                'retries' => 0
            ]) + $options);

            // cache collection references
            $collections = [];

            $out = [];
            while ($generator->valid()) {
                $result = $generator->current();

                if (isset($result['document']) && $result['document']) {
                    $collectionName = $this->parentPath($result['document']['name']);
                    if (!isset($collections[$collectionName])) {
                        $collections[$collectionName] = new CollectionReference(
                            $this->connection,
                            $this->valueMapper,
                            $collectionName
                        );
                    }

                    $ref = new DocumentReference(
                        $this->connection,
                        $this->valueMapper,
                        $collections[$collectionName],
                        $result['document']['name']
                    );

                    $document = $result['document'];
                    $document['readTime'] = $result['readTime'];

                    $out[] = $this->createSnapshotWithData($this->valueMapper, $ref, $document);
                }

                $generator->next();
            }

            return $out;
        });

        return new QuerySnapshot($this, $rows);
    }