Repository navigation
Question aggregates by location level, quick report aggregates and polling station counts - #1127
Merged
Merged
Conversation
added 5 commits
October 20, 2026 12:06
…ent and citizen reports - New :aggregatedByLevel endpoints for form submissions, incident reports and citizen reports aggregate the answers to one question, overall and per distinct Level1..<level> location path. They return 404 when the form is not available to the ngo or does not contain the question. - The level is a new LocationLevel smart enum (Level1..Level5). - The aggregation runs in the database: the shared "AggregateQuestionByLevel" function and one entry function per report type.
- quick-reports:aggregated returns the totals and every Level1..Level5 location (with Id, Level and ParentId); quick-reports:aggregatedByLevel returns the locations of one level. - Each entry counts quick reports, polling stations and observers, with histograms per incident category, location type and follow-up status (every value listed, 0 when not reported).
The list ignored SortColumnName=status and observerName (sent by the web app), and its fallback sort matched no column, so rows came back unordered. Rows with the same sort value are now ordered by display name and id, so pages do not overlap.
Single select, multi select and rating aggregates computed in memory (V1 aggregated endpoints) now fill PollingStationsHistogram with the number of distinct polling stations where each option / value was picked, as the database aggregation does. It is not set when the submissions have no polling station.
Every answer aggregate (all question types, overall and in each LocationAggregates entry, V1 and V2 and the by-level aggregates) now has PollingStationsCount: the distinct polling stations of the submissions that answered the question, and, for citizen reports, LocationsCount: their distinct locations. A place's PollingStationsCount counts the stations of all its submissions, including ones that skipped the question. - In memory: BaseAnswerAggregate tracks the distinct station / location ids it aggregates (null when none had one); citizen reports pass their location id. - Database: migration AddQuestionAggregatePlaceCounts recreates "AggregateAnswers" with the two counts (0 for an unanswered question); Down restores the previous definition.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| public void Aggregate(Guid submissionId, Guid monitoringObserverId, BaseAnswer answer) | ||
| /// <param name="pollingStationId">The polling station of the submission; not set for citizen reports.</param> | ||
| /// <param name="locationId">The location of the citizen report; only set for citizen reports.</param> | ||
| public void Aggregate(Guid submissionId, Guid monitoringObserverId, BaseAnswer answer, Guid? pollingStationId = null, Guid? locationId = null) |
| public void Aggregate(Guid submissionId, Guid monitoringObserverId, BaseAnswerModel answer) | ||
| /// <param name="pollingStationId">The polling station of the submission; not set for citizen reports.</param> | ||
| /// <param name="locationId">The location of the citizen report; only set for citizen reports.</param> | ||
| public void Aggregate(Guid submissionId, Guid monitoringObserverId, BaseAnswerModel answer, Guid? pollingStationId = null, Guid? locationId = null) |
| private readonly Dictionary<TKey, HashSet<Guid>> _pollingStations; | ||
|
|
||
| /// <param name="keys">The options / values, so that the ones never picked are counted as 0.</param> | ||
| public DistinctPollingStations(IEnumerable<TKey> keys) |
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes
Question aggregates by location level
…QuestionAggregateByLevelfunctions).Quick reports aggregates
Polling stations per option
pollingStationsHistogramin memory too (V1), as the database aggregation already does.Polling stations per question
pollingStationsCount: the distinct polling stations of the submissions that answered the question. Citizen reports getlocationsCountinstead.locationAggregatesentry, and in the by-level aggregates, for V1 and V2.pollingStationsCountcounts the stations of all its submissions, including ones that skipped the question. The web app uses the new count to show "63 answers in 29 polling stations" per place.AddQuestionAggregatePlaceCountsrecreates"AggregateAnswers"with the two counts. Its Down restores the previous definition.Fix
Testing
dotnet test tests/Module.Answers.UnitTests: 112 of 112 pass. New tests cover distinct counting, null when no answer has a station or location, and reading the counts back from database JSON.dotnet test tests/Vote.Monitor.Api.IntegrationTests --filter GetAggregatedTests: 5 of 5 pass on Testcontainers Postgres with every migration applied."AggregateAnswers"was also called directly on sample data:LocationsCount.Not covered
dotnet ef(7.0) is older than the project's EF 8.