diff --git a/ara/api/serializers.py b/ara/api/serializers.py
index f6656a01..bfbfd33e 100644
--- a/ara/api/serializers.py
+++ b/ara/api/serializers.py
@@ -74,8 +74,7 @@ class FileSha1Serializer(serializers.ModelSerializer):
 
 
 #######
-# Simple serializers provide lightweight representations of objects without
-# nested or large fields.
+# Simple serializers provide lightweight representations of objects suitable for inclusion in other objects
 #######
 
 
@@ -96,108 +95,27 @@ class SimplePlaybookSerializer(ItemCountSerializer):
 class SimplePlaySerializer(ItemCountSerializer):
     class Meta:
         model = models.Play
-        exclude = ("uuid", "created", "updated")
+        exclude = ("playbook", "uuid", "created", "updated")
 
 
 class SimpleTaskSerializer(ItemCountSerializer, TaskPathSerializer):
     class Meta:
         model = models.Task
-        exclude = ("tags", "created", "updated")
+        exclude = ("playbook", "play", "created", "updated")
 
-
-class SimpleResultSerializer(ResultStatusSerializer):
-    class Meta:
-        model = models.Result
-        exclude = ("content", "created", "updated")
+    tags = ara_fields.CompressedObjectField(read_only=True)
 
 
 class SimpleHostSerializer(serializers.ModelSerializer):
     class Meta:
         model = models.Host
-        exclude = ("facts", "created", "updated")
+        exclude = ("playbook", "facts", "created", "updated")
 
 
 class SimpleFileSerializer(FileSha1Serializer):
     class Meta:
         model = models.File
-        exclude = ("content", "created", "updated")
-
-
-class SimpleRecordSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = models.Record
-        exclude = ("value", "created", "updated")
-
-
-#######
-# Nested serializers returns optimized data within the context of another object.
-# For example: when retrieving a playbook, we'll already have the playbook id
-# so it is not necessary to include it in nested objects.
-#######
-
-
-class NestedPlaybookFileSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = models.File
-        exclude = ("content", "created", "updated", "playbook")
-
-
-class NestedPlaybookHostSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = models.Host
-        fields = ("id", "name")
-
-
-class NestedPlaybookResultSerializer(ResultStatusSerializer):
-    class Meta:
-        model = models.Result
-        exclude = ("content", "created", "updated", "playbook", "play", "task")
-
-    host = NestedPlaybookHostSerializer(read_only=True)
-
-
-class NestedPlaybookTaskSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = models.Task
-        exclude = ("playbook", "created", "updated")
-
-    tags = ara_fields.CompressedObjectField(read_only=True)
-    file = NestedPlaybookFileSerializer(read_only=True)
-    results = serializers.SerializerMethodField()
-
-    @staticmethod
-    def get_results(obj):
-        results = obj.results.all().order_by("-id")
-        return NestedPlaybookResultSerializer(results, many=True).data
-
-
-class NestedPlaybookRecordSerializer(serializers.ModelSerializer):
-    class Meta:
-        model = models.Record
-        exclude = ("playbook", "value", "created", "updated")
-
-
-class NestedPlaybookPlaySerializer(serializers.ModelSerializer):
-    class Meta:
-        model = models.Play
-        exclude = ("playbook", "uuid", "created", "updated")
-
-    tasks = serializers.SerializerMethodField()
-
-    @staticmethod
-    def get_tasks(obj):
-        tasks = obj.tasks.all().order_by("-id")
-        return NestedPlaybookTaskSerializer(tasks, many=True).data
-
-
-class NestedPlayTaskSerializer(TaskPathSerializer):
-    class Meta:
-        model = models.Task
-        exclude = ("playbook", "play", "created", "updated")
-
-    tags = ara_fields.CompressedObjectField(read_only=True)
-    results = NestedPlaybookResultSerializer(read_only=True, many=True)
-    file = NestedPlaybookFileSerializer(read_only=True)
+        exclude = ("playbook", "content", "created", "updated")
 
 
 #######
@@ -219,15 +137,6 @@ class DetailedPlaybookSerializer(ItemCountSerializer):
 
     arguments = ara_fields.CompressedObjectField(default=ara_fields.EMPTY_DICT, read_only=True)
     labels = SimpleLabelSerializer(many=True, read_only=True, default=[])
-    hosts = SimpleHostSerializer(many=True, read_only=True, default=[])
-    files = SimpleFileSerializer(many=True, read_only=True, default=[])
-    records = NestedPlaybookRecordSerializer(many=True, read_only=True, default=[])
-    plays = serializers.SerializerMethodField()
-
-    @staticmethod
-    def get_plays(obj):
-        plays = obj.plays.all().order_by("-id")
-        return NestedPlaybookPlaySerializer(plays, many=True).data
 
 
 class DetailedPlaySerializer(ItemCountSerializer):
@@ -236,7 +145,6 @@ class DetailedPlaySerializer(ItemCountSerializer):
         fields = "__all__"
 
     playbook = SimplePlaybookSerializer(read_only=True)
-    tasks = NestedPlayTaskSerializer(many=True, read_only=True, default=[])
 
 
 class DetailedTaskSerializer(ItemCountSerializer, TaskPathSerializer):
@@ -247,7 +155,6 @@ class DetailedTaskSerializer(ItemCountSerializer, TaskPathSerializer):
     playbook = SimplePlaybookSerializer(read_only=True)
     play = SimplePlaySerializer(read_only=True)
     file = SimpleFileSerializer(read_only=True)
-    results = NestedPlaybookResultSerializer(many=True, read_only=True, default=[])
     tags = ara_fields.CompressedObjectField(read_only=True)
 
 
diff --git a/ara/ui/templates/playbook.html b/ara/ui/templates/playbook.html
index a2d26f07..ac2b241c 100644
--- a/ara/ui/templates/playbook.html
+++ b/ara/ui/templates/playbook.html
@@ -7,7 +7,7 @@
     <div class="pf-c-card__body">
         <details id="records">
             <summary>Records</summary>
-            {% if playbook.items.records %}
+            {% if records %}
             <ul class="pf-c-list">
                 {% for record in playbook.records %}
                 <li><a href="../records/{{ record.id }}.html">{{ record.key }}</a></li>
@@ -20,7 +20,7 @@
         <details id="files">
             <summary>Files</summary>
             <ul class="pf-c-list">
-                {% for file in playbook.files %}
+                {% for file in files %}
                 <li><a href="../files/{{ file.id }}.html">{{ file.path }}</a></li>
                 {% endfor %}
             </ul>
@@ -74,7 +74,7 @@
                     </tr>
                 </thead>
                 <tbody>
-                    {% for host in playbook.hosts %}
+                    {% for host in hosts %}
                     <tr>
                         <td role="cell" data-label="Hostname" class="pf-m-fit-content">
                             <a href="../hosts/{{ host.id }}.html">{{ host.name }}</a>
@@ -117,9 +117,7 @@
                     </tr>
                 </thead>
                 <tbody>
-                    {% for play in playbook.plays %}
-                    {% for task in play.tasks %}
-                    {% for result in task.results %}
+                    {% for result in results %}
                     <tr role="row">
                         <td role="cell" data-label="Status" class="pf-c-table__icon pf-m-fit-content">
                             {% include "partials/result_status_icon.html" with status=result.status %}
@@ -128,10 +126,10 @@
                             {{ result.host.name }}
                         </td>
                         <td role="cell" data-label="Name" class="pf-m-fit-content">
-                            <a href="../results/{{ result.id }}.html">{{ task.name }}</a>
+                            <a href="../results/{{ result.id }}.html">{{ result.task.name }}</a>
                         </td>
                         <td role="cell" data-label="Action" class="pf-m-fit-content">
-                            <a href="../files/{{ task.file.id }}.html#line-{{ task.lineno }}">{{ task.action }}</a>
+                            <a href="../files/{{ task.file.id }}.html#line-{{ result.task.lineno }}">{{ result.task.action }}</a>
                         </td>
                         <td role="cell" data-label="Duration" class="pf-m-fit-content">
                             {{ result.duration | format_duration }}
@@ -141,8 +139,6 @@
                         </td>
                     </tr>
                     {% endfor %}
-                    {% endfor %}
-                    {% endfor %}
                 </tbody>
             </table>
         </details>
diff --git a/ara/ui/views.py b/ara/ui/views.py
index e4d374d3..00fe5623 100644
--- a/ara/ui/views.py
+++ b/ara/ui/views.py
@@ -68,9 +68,35 @@ class Playbook(generics.RetrieveAPIView):
     template_name = "playbook.html"
 
     def get(self, request, *args, **kwargs):
-        playbook = self.get_object()
-        serializer = serializers.DetailedPlaybookSerializer(playbook)
-        return Response({"playbook": serializer.data})
+        playbook = serializers.DetailedPlaybookSerializer(self.get_object())
+        hosts = serializers.ListHostSerializer(
+            models.Host.objects.filter(playbook=playbook.data["id"]).all(), many=True
+        )
+        files = serializers.ListFileSerializer(
+            models.File.objects.filter(playbook=playbook.data["id"]).all(), many=True
+        )
+        records = serializers.ListRecordSerializer(
+            models.Record.objects.filter(playbook=playbook.data["id"]).all(), many=True
+        )
+        results = serializers.ListResultSerializer(
+            models.Result.objects.filter(playbook=playbook.data["id"]).all(), many=True
+        )
+
+        for result in results.data:
+            task_id = result["task"]
+            result["task"] = serializers.SimpleTaskSerializer(models.Task.objects.get(pk=task_id)).data
+            host_id = result["host"]
+            result["host"] = serializers.SimpleHostSerializer(models.Host.objects.get(pk=host_id)).data
+
+        # fmt: off
+        return Response({
+            "playbook": playbook.data,
+            "hosts": hosts.data,
+            "files": files.data,
+            "records": records.data,
+            "results": results.data
+        })
+        # fmt: on
 
 
 class Host(generics.RetrieveAPIView):
diff --git a/doc/source/api-usage.rst b/doc/source/api-usage.rst
index a58d4216..7ea721de 100644
--- a/doc/source/api-usage.rst
+++ b/doc/source/api-usage.rst
@@ -82,25 +82,30 @@ Here's a code example to help you get started:
     # If there are any results from our query, get more information about the
     # failure and print something helpful
     template = "{timestamp}: {host} failed '{task}' ({task_file}:{lineno})"
-    for playbook in playbooks["results"]:
-        # Get a detailed version of the playbook that provides additional context
-        detailed_playbook = client.get("/api/v1/playbooks/%s" % playbook["id"])
 
-        # Iterate through the playbook to get the context
-        # Playbook -> Play -> Task -> Result <- Host
-        for play in detailed_playbook["plays"]:
-            for task in play["tasks"]:
-                for result in task["results"]:
-                    if result["status"] in ["failed", "unreachable"]:
-                        print(template.format(
-                            timestamp=result["ended"],
-                            host=result["host"]["name"],
-                            task=task["name"],
-                            task_file=task["file"]["path"],
-                            lineno=task["lineno"]
-                        ))
+    for playbook in playbooks["results"]:
+        # Get failed results for the playbook
+        results = client.get("/api/v1/results?playbook=%s" % playbook["id"])
+
+        # For each result, print the task and host information
+        for result in results["results"]:
+            task = client.get("/api/v1/tasks/%s" % result["task"])
+            host = client.get("/api/v1/hosts/%s" % result["host"])
+
+            print(template.format(
+                timestamp=result["ended"],
+                host=host["name"],
+                task=task["name"],
+                task_file=task["path"],
+                lineno=task["lineno"]
+            ))
 
 Running this script would then provide an output that looks like the following::
 
-    2019-03-20T16:18:41.710765: localhost failed 'smoke-tests : Return false' (tests/integration/roles/smoke-tests/tasks/test-ops.yaml:25)
-    2019-03-20T16:19:17.332663: localhost failed 'fail' (tests/integration/failed.yaml:22)
+    2020-04-18T17:16:13.394056Z: aio1_repo_container-0c92f7a2 failed 'repo_server : Install EPEL gpg keys' (/home/zuul/src/opendev.org/openstack/openstack-ansible-repo_server/tasks/repo_install.yml:16)
+    2020-04-18T17:14:59.930995Z: aio1_repo_container-0c92f7a2 failed 'repo_server : File and directory setup (root user)' (/home/zuul/src/opendev.org/openstack/openstack-ansible-repo_server/tasks/repo_pre_install.yml:78)
+    2020-04-18T17:14:57.909155Z: aio1_repo_container-0c92f7a2 failed 'repo_server : Git service data folder setup' (/home/zuul/src/opendev.org/openstack/openstack-ansible-repo_server/tasks/repo_pre_install.yml:70)
+    2020-04-18T17:14:57.342091Z: aio1_repo_container-0c92f7a2 failed 'repo_server : Check if the git folder exists already' (/home/zuul/src/opendev.org/openstack/openstack-ansible-repo_server/tasks/repo_pre_install.yml:65)
+    2020-04-18T17:14:56.793499Z: aio1_repo_container-0c92f7a2 failed 'repo_server : Drop repo pre/post command script' (/home/zuul/src/opendev.org/openstack/openstack-ansible-repo_server/tasks/repo_pre_install.yml:53)
+    2020-04-18T17:14:54.507660Z: aio1_repo_container-0c92f7a2 failed 'repo_server : File and directory setup (non-root user)' (/home/zuul/src/opendev.org/openstack/openstack-ansible-repo_server/tasks/repo_pre_install.yml:32)
+    2020-04-18T17:14:51.281530Z: aio1_repo_container-0c92f7a2 failed 'repo_server : Create the nginx system user' (/home/zuul/src/opendev.org/openstack/openstack-ansible-repo_server/tasks/repo_pre_install.yml:22)
diff --git a/tests/integration/lookups.yaml b/tests/integration/lookups.yaml
index 0b4ca780..9ea2c8d9 100644
--- a/tests/integration/lookups.yaml
+++ b/tests/integration/lookups.yaml
@@ -26,11 +26,6 @@
           - playbook.ansible_version == ansible_version.full
           - playbook_dir in playbook.path
           - "'tests/integration/lookups.yaml' in playbook.path"
-          - "playbook.files | length == playbook['items']['files']"
-          - "playbook.hosts | length == playbook['items']['hosts']"
-          - "playbook.plays | length == playbook['items']['plays']"
-          - "tasks.results | length == playbook['items']['tasks']"
-          - "results.results | length == playbook['items']['results']"
 
     #####
     # Examples taken from docs on Ansible plugins and use cases