Hi!
I would like to create a JSON structure of chosen objects (animals) with corresponding events in one database hit.
The model represents animals and different types of events that happened to them:
class Animal(models.Model):
life_number = models.TextField(primary_key=True)
birthday = models.DateField(blank=True, null=True)
class Inseminacja(models.Model):
cow = models.ForeignKey(Animal, models.DO_NOTHING, db_column='cow_life_number')
date = models.DateTimeField()
number = models.IntegerField()
class WynikBadania(models.Model):
animal = models.ForeignKey(Animal, models.DO_NOTHING, db_column='anilifenumber')
date_entered = models.DateTimeField(db_column='timestamp')
I use my JsonAgg and JsonBuildObject functions submitted to Trac at:
https://code.djangoproject.com/ticket/26327#no1>>> qs = Animal.objects.filter(pk='PL005257066205').annotate(
ins = JsonAgg(JsonBuildObject([F('inseminacja__date'),F('inseminacja__number')], output_field=CharField())),
examinations = JsonAgg(JsonBuildObject([F('wynikbadania__date_entered')], output_field=CharField()))
)
The resulting query naturally results in cartesian product of the events, which is exactly my problem:
>>> str(qs.query)
'SELECT
"animal"."life_number",
"animal"."birthday",
JSON_AGG(JSON_BUILD_OBJECT(\'timestamp\',"wynikbadania"."timestamp")) AS "examinations",
JSON_AGG(JSON_BUILD_OBJECT(\'date\',"inseminacja"."date",\'number\',"inseminacja"."number")) AS "ins"
FROM "animal"
LEFT OUTER JOIN "wynikbadania" ON ("animal"."life_number" = "wynikbadania"."anilifenumber")
LEFT OUTER JOIN "inseminacja" ON ("animal"."life_number" = "inseminacja"."cow_life_number")
WHERE "animal"."life_number" = PL005257066205
GROUP BY "animal"."life_number"'
>>> qs.values()
[{
'examinations': [
{u'timestamp': u'2014-11-20T12:41:54'},
{u'timestamp': u'2014-11-20T12:41:54'},
{u'timestamp': u'2015-07-13T11:41:08.40319'},
{u'timestamp': u'2015-07-13T11:41:08.40319'}
],
'birthday': None,
'ins': [
{u'date': u'2013-11-16T15:00:00', u'number': 1},
{u'date': u'2013-12-09T10:00:00', u'number': 2},
{u'date': u'2013-11-16T15:00:00', u'number': 1},
{u'date': u'2013-12-09T10:00:00', u'number': 2}
],
'life_number': u'PL005257066205'
}]
I don't know exact SQL query that should be used.
Using DISTINCT is not possible, as "JSON_AGG(DISTINCT JSON_BUILD_OBJECT(" results in "ERROR: could not identify an equality operator for type json".
Using GROUP BY "animal"."life_number", "wynikbadania"."timestamp","inseminacja"."date" naturally results in 4 separate records.
Do you have any ideas?
Best wishes,
Tomasz