summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorabhiabhi94 <13880786+abhiabhi94@users.noreply.github.com>2021-07-15 19:09:40 +0530
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-07-26 11:23:51 +0200
commit5a634a7b6f248e5dead65f420ec5d30acd9724bf (patch)
tree1a1a748600521b1b0813c8a090d840127b2681d8
parent325d7710ce9f6155bb55610ad6b4580d31263557 (diff)
Fixed #32906 -- Added docs and tests for using key and index lookups on JSONBAgg results.
Co-authored-by: Mariusz Felisiak <felisiak.mariusz@gmail.com>
-rw-r--r--docs/ref/contrib/postgres/aggregates.txt26
-rw-r--r--tests/postgres_tests/test_aggregates.py45
2 files changed, 69 insertions, 2 deletions
diff --git a/docs/ref/contrib/postgres/aggregates.txt b/docs/ref/contrib/postgres/aggregates.txt
index 6d85d5c478..9223f17ab8 100644
--- a/docs/ref/contrib/postgres/aggregates.txt
+++ b/docs/ref/contrib/postgres/aggregates.txt
@@ -125,7 +125,8 @@ General-purpose aggregation functions
.. class:: JSONBAgg(expressions, distinct=False, filter=None, default=None, ordering=(), **extra)
Returns the input values as a ``JSON`` array, or ``default`` if there are
- no values.
+ no values. You can query the result using :lookup:`key and index lookups
+ <jsonfield.key>`.
.. attribute:: distinct
@@ -145,6 +146,29 @@ General-purpose aggregation functions
Examples are the same as for :attr:`ArrayAgg.ordering`.
+ Usage example::
+
+ class Room(models.Model):
+ number = models.IntegerField(unique=True)
+
+ class HotelReservation(model.Model):
+ room = models.ForeignKey('Room', on_delete=models.CASCADE)
+ start = models.DateTimeField()
+ end = models.DateTimeField()
+ requirements = models.JSONField(blank=True, null=True)
+
+ >>> from django.contrib.postgres.aggregates import JSONBAgg
+ >>> Room.objects.annotate(
+ ... requirements=JSONBAgg(
+ ... 'hotelreservation__requirements',
+ ... ordering='-hotelreservation__start',
+ ... )
+ ... ).filter(requirements__0__sea_view=True).values('number', 'requirements')
+ <QuerySet [{'number': 102, 'requirements': [
+ {'parking': False, 'sea_view': True, 'double_bed': False},
+ {'parking': True, 'double_bed': True}
+ ]}]>
+
.. deprecated:: 4.0
If there are no rows and ``default`` is not provided, ``JSONBAgg``
diff --git a/tests/postgres_tests/test_aggregates.py b/tests/postgres_tests/test_aggregates.py
index 7ae7b16c9f..a963aae3c4 100644
--- a/tests/postgres_tests/test_aggregates.py
+++ b/tests/postgres_tests/test_aggregates.py
@@ -4,10 +4,11 @@ from django.db.models import (
from django.db.models.fields.json import KeyTextTransform, KeyTransform
from django.db.models.functions import Cast, Concat, Substr
from django.test.utils import Approximate, ignore_warnings
+from django.utils import timezone
from django.utils.deprecation import RemovedInDjango50Warning
from . import PostgreSQLTestCase
-from .models import AggregateTestModel, StatTestModel
+from .models import AggregateTestModel, HotelReservation, Room, StatTestModel
try:
from django.contrib.postgres.aggregates import (
@@ -392,6 +393,48 @@ class TestGeneralAggregate(PostgreSQLTestCase):
)
self.assertEqual(values, {'jsonbagg': ['en', 'pl']})
+ def test_jsonb_agg_key_index_transforms(self):
+ room101 = Room.objects.create(number=101)
+ room102 = Room.objects.create(number=102)
+ datetimes = [
+ timezone.datetime(2018, 6, 20),
+ timezone.datetime(2018, 6, 24),
+ timezone.datetime(2018, 6, 28),
+ ]
+ HotelReservation.objects.create(
+ datespan=(datetimes[0].date(), datetimes[1].date()),
+ start=datetimes[0],
+ end=datetimes[1],
+ room=room102,
+ requirements={'double_bed': True, 'parking': True},
+ )
+ HotelReservation.objects.create(
+ datespan=(datetimes[1].date(), datetimes[2].date()),
+ start=datetimes[1],
+ end=datetimes[2],
+ room=room102,
+ requirements={'double_bed': False, 'sea_view': True, 'parking': False},
+ )
+ HotelReservation.objects.create(
+ datespan=(datetimes[0].date(), datetimes[2].date()),
+ start=datetimes[0],
+ end=datetimes[2],
+ room=room101,
+ requirements={'sea_view': False},
+ )
+ values = Room.objects.annotate(
+ requirements=JSONBAgg(
+ 'hotelreservation__requirements',
+ ordering='-hotelreservation__start',
+ )
+ ).filter(requirements__0__sea_view=True).values('number', 'requirements')
+ self.assertSequenceEqual(values, [
+ {'number': 102, 'requirements': [
+ {'double_bed': False, 'sea_view': True, 'parking': False},
+ {'double_bed': True, 'parking': True},
+ ]},
+ ])
+
def test_string_agg_array_agg_ordering_in_subquery(self):
stats = []
for i, agg in enumerate(AggregateTestModel.objects.order_by('char_field')):