diff --git a/lib/models/ban.cjs b/lib/models/ban.cjs index 32690d62..cf656a0d 100644 --- a/lib/models/ban.cjs +++ b/lib/models/ban.cjs @@ -1,71 +1,171 @@ -const {sumBy} = require('lodash') const mongo = require('../util/mongo.cjs') -const {getCommunes, getCommune} = require('../util/cog.cjs') -async function computeStats() { - const communes = getCommunes() +const defaultStatsOfDistrictsDataResult = { + nbAdresses: 0, + nbAdressesCertifiees: 0, + nbCommunesCouvertes: 0, + populationCouverte: 0, + nbCommunesAvecBanId: 0, + nbAdressesAvecBanId: 0, +} + +const defaultStatsOfAddressesDataResult = { + nbNumeroWithBanId: 0, + countDistinctCodeCommune: 0, +} - const france = { - population: sumBy(communes, 'population'), - nbCommunes: communes.length +async function getStatsOfDistricts(cog = []) { + const communesCollection = mongo.db.collection('communes') + const mongoRequestFilters = { + ban: null, + bal: {typeComposition: 'bal'}, + computed: {typeComposition: {$ne: 'bal'}}, } + const statsOfDistrictsPipelineResult = groupName => ( + { + $group: { + _id: `group_${groupName}`, + nbAdresses: {$sum: '$nbNumeros'}, + nbAdressesCertifiees: {$sum: '$nbNumerosCertifies'}, + nbCommunesCouvertes: {$sum: 1}, + populationCouverte: {$sum: '$population'}, + nbCommunesIdSocle: {$sum: { + $cond: [{$eq: ['$withBanId', true]}, 1, 0] + }}, + nbAdressesIdSocle: {$sum: { + $cond: [{$eq: ['$withBanId', true]}, '$nbNumeros', 0] + }} + } + } + ) - const communesRecords = await mongo.db.collection('communes').find({}).toArray() - const banCommunesRecords = communesRecords.filter(c => c.nbNumeros > 0) + const mongoRequest = [ + ...(cog && cog.length > 0 ? [{$match: {codeCommune: {$in: cog}}}] : []), + { + $facet: Object.fromEntries( + Object + .entries(mongoRequestFilters) + .map(([groupName, filter]) => [ + groupName, [ + ...(filter ? [{$match: filter}] : []), + statsOfDistrictsPipelineResult(groupName) + ] + ]) + ) + } + ] - const ban = { - nbAdresses: sumBy(banCommunesRecords, 'nbNumeros'), - nbAdressesCertifiees: sumBy(banCommunesRecords, 'nbNumerosCertifies'), - nbCommunesCouvertes: banCommunesRecords.length, - populationCouverte: sumBy(banCommunesRecords, 'population'), - nbCommunesAvecBanId: sumBy(banCommunesRecords, 'withBanId') + return communesCollection.aggregate(mongoRequest).toArray() +} + +async function getStatsOfAddresses(cog) { + const numerosCollection = mongo.db.collection('numeros') + const mongoRequestFilters = { + ban: null, + bal: {sources: 'bal'}, + computed: {sources: {$not: {$eq: ['bal']}}}, } - const balCommunesRecords = communesRecords.filter(c => c.typeComposition === 'bal') + const statsOfBanIdPipelinesResult = [ + { + $group: { + _id: null, + nbNumeroWithBanId: {$sum: 1}, + distinctCodeCommune: {$addToSet: '$codeCommune'} + } + }, + { + $project: { + _id: 0, + nbNumeroWithBanId: '$nbNumeroWithBanId', + countDistinctCodeCommune: {$size: '$distinctCodeCommune'} + } + }, + ] - const bal = { - nbAdresses: sumBy(balCommunesRecords, 'nbNumeros'), - nbAdressesCertifiees: sumBy(balCommunesRecords, 'nbNumerosCertifies'), - nbCommunesCouvertes: balCommunesRecords.length, - populationCouverte: sumBy(balCommunesRecords, 'population'), - nbCommunesAvecBanId: sumBy(balCommunesRecords, 'withBanId') - } + const mongoRequest = [ + ...(cog && cog.length > 0 ? [{$match: {codeCommune: {$in: cog}}}] : []), + {$match: {banId: {$exists: true, $ne: null}}}, + { + $facet: Object.fromEntries( + Object + .entries(mongoRequestFilters) + .map(([groupName, filter]) => [ + groupName, [ + ...(filter ? [{$match: filter}] : []), + ...statsOfBanIdPipelinesResult, + ] + ]) + ) + } + ] - return {france, ban, bal} + return numerosCollection.aggregate(mongoRequest).toArray() } -async function computeFilteredStats(codesCommune) { - const communes = codesCommune.map(code => getCommune(code)) +async function getFullStats(codesCommune) { + const statsByCog = getStatsOfDistricts(codesCommune) + const statsOfNumerosCollection = getStatsOfAddresses(codesCommune) - const total = { - population: sumBy(communes, 'population'), - nbCommunes: communes.length + const [ + [{ban: banDistrictStat, bal: balDistrictStat, computed: computedDistrictStat}], + [{ban: banBanIdStat, bal: balBanIdStat, computed: computedBanIdStat}], + ] = await Promise.all([statsByCog, statsOfNumerosCollection]) + + const ban = { + ...defaultStatsOfDistrictsDataResult, + ...banDistrictStat?.[0], + ...defaultStatsOfAddressesDataResult, + ...banBanIdStat?.[0], + } + + const bal = { + ...defaultStatsOfDistrictsDataResult, + ...balDistrictStat?.[0], + ...defaultStatsOfAddressesDataResult, + ...balBanIdStat?.[0], } - const communesRecords = await mongo.db.collection('communes').find({ - codeCommune: {$in: codesCommune} - }).toArray() - const banCommunesRecords = communesRecords.filter(c => c.nbNumeros > 0) + const computed = { + ...defaultStatsOfDistrictsDataResult, + ...computedDistrictStat?.[0], + ...defaultStatsOfAddressesDataResult, + ...computedBanIdStat?.[0], + } - const ban = { - nbAdresses: sumBy(banCommunesRecords, 'nbNumeros'), - nbAdressesCertifiees: sumBy(banCommunesRecords, 'nbNumerosCertifies'), - nbCommunesCouvertes: banCommunesRecords.length, - populationCouverte: sumBy(banCommunesRecords, 'population'), - nbCommunesAvecBanId: sumBy(banCommunesRecords, 'withBanId') + const total = { + population: ban?.populationCouverte || 0, + nbCommunes: ban?.nbCommunesCouvertes || 0, + } + + return { + total, + ban, + bal, + computed, } +} - const balCommunesRecords = communesRecords.filter(c => c.typeComposition === 'bal') +async function computeStats() { + const {total, ban, bal, computed} = await getFullStats() - const bal = { - nbAdresses: sumBy(balCommunesRecords, 'nbNumeros'), - nbAdressesCertifiees: sumBy(balCommunesRecords, 'nbNumerosCertifies'), - nbCommunesCouvertes: balCommunesRecords.length, - populationCouverte: sumBy(balCommunesRecords, 'population'), - nbCommunesAvecBanId: sumBy(balCommunesRecords, 'withBanId') + return { + france: total, + ban, + bal, + assemblage: computed, } +} - return {total, ban, bal} +async function computeFilteredStats(codesCommune) { + const {total, ban, bal, computed} = await getFullStats(codesCommune) + + return { + total, + ban, + bal, + assemblage: computed, + } } module.exports = {computeStats, computeFilteredStats} diff --git a/lib/util/mongo.cjs b/lib/util/mongo.cjs index 7eeb9695..dee5268d 100644 --- a/lib/util/mongo.cjs +++ b/lib/util/mongo.cjs @@ -31,6 +31,7 @@ class Mongo { await this.db.collection('numeros').createIndex({banIdSecondaryCommonToponyms: 1}) await this.db.collection('numeros').createIndex({banIdDistrict: 1}) await this.db.collection('numeros').createIndex({tiles: 1}) + await this.db.collection('numeros').createIndex({sources: 1}) await this.db.collection('pseudo_codes_voies').createIndex({codeCommune: 1}) await this.db.collection('sources_adresses').createIndex({codeCommune: 1, dataSource: 1}) await this.db.collection('sources_parts').createIndex({source: 1, part: 1}) @@ -38,6 +39,7 @@ class Mongo { await this.db.collection('sources_communes').createIndex({source: 1, part: 1}) await this.db.collection('communes').createIndex({compositionAskedAt: 1}, {sparse: true}) await this.db.collection('communes').createIndex({codeCommune: 1}, {unique: true}) + await this.db.collection('communes').createIndex({typeComposition: 1}) await this.db.collection('communes').createIndex({banId: 1}) await this.db.collection('metrics').createIndex({name: 1, date: 1}, {unique: true}) }