adminmate-express-mongoose
Advanced tools
Comparing version 1.3.1 to 1.3.2
{ | ||
"name": "adminmate-express-mongoose", | ||
"version": "1.3.1", | ||
"version": "1.3.2", | ||
"description": "Adminmate Express/Mongoose connector", | ||
@@ -26,3 +26,4 @@ "author": "Marc Delalonde", | ||
"dependencies": { | ||
"adminmate-express-core": "^1.2.0", | ||
"@hapi/joi": "^17.1.1", | ||
"adminmate-express-core": "~1.2.0", | ||
"lodash": "^4.17.21", | ||
@@ -29,0 +30,0 @@ "moment": "^2.29.1", |
@@ -0,2 +1,26 @@ | ||
const Joi = require('@hapi/joi'); | ||
module.exports = async (currentModel, data) => { | ||
const paramsSchema = Joi.object({ | ||
type: Joi.string().required(), | ||
model: Joi.string().required(), | ||
operation: Joi.string().required(), | ||
group_by: Joi.string().required(), | ||
field: Joi.alternatives().conditional('operation', { | ||
not: 'count', | ||
then: Joi.string().required(), | ||
otherwise: Joi.string().optional() | ||
}), | ||
limit: Joi.number().optional() | ||
}); | ||
// Validate params | ||
const { error } = paramsSchema.validate(data); | ||
if (error) { | ||
return { | ||
success: false, | ||
message: error.details[0].message | ||
}; | ||
} | ||
let _value = 1; | ||
@@ -7,27 +31,35 @@ if (data.field && ['sum', 'avg'].includes(data.operation)) { | ||
const repartitionData = await currentModel | ||
.aggregate([ | ||
{ | ||
$group: { | ||
_id: `$${data.group_by}`, | ||
count: data.operation === 'avg' ? { $avg: _value } : { $sum: _value }, | ||
try { | ||
const repartitionData = await currentModel | ||
.aggregate([ | ||
{ | ||
$group: { | ||
_id: `$${data.group_by}`, | ||
count: data.operation === 'avg' ? { $avg: _value } : { $sum: _value }, | ||
} | ||
}, | ||
{ | ||
$project: { | ||
key: '$_id', | ||
value: '$count', | ||
_id: false | ||
} | ||
} | ||
}, | ||
{ | ||
$project: { | ||
key: '$_id', | ||
value: '$count', | ||
_id: false | ||
} | ||
]) | ||
.sort({ key: 1 }); | ||
return { | ||
success: true, | ||
data: { | ||
config: null, | ||
data: repartitionData | ||
} | ||
]) | ||
.sort({ key: 1 }); | ||
return { | ||
success: true, | ||
data: { | ||
config: null, | ||
data: repartitionData | ||
} | ||
}; | ||
}; | ||
} | ||
catch(e) { | ||
return { | ||
success: false, | ||
message: e.message | ||
}; | ||
} | ||
}; |
@@ -0,4 +1,29 @@ | ||
const Joi = require('@hapi/joi'); | ||
const fnHelper = require('../helpers/functions'); | ||
module.exports = async (currentModel, data) => { | ||
const paramsSchema = Joi.object({ | ||
type: Joi.string().required(), | ||
model: Joi.string().required(), | ||
field: Joi.string().required(), | ||
relationship_model: Joi.string().required(), | ||
relationship_model_ref_field: Joi.string().required(), | ||
relationship_operation: Joi.string().required(), | ||
relationship_field: Joi.alternatives().conditional('relationship_operation', { | ||
not: 'count', | ||
then: Joi.string().required(), | ||
otherwise: Joi.string() | ||
}), | ||
limit: Joi.number().optional(), | ||
}); | ||
// Validate params | ||
const { error } = paramsSchema.validate(data); | ||
if (error) { | ||
return { | ||
success: false, | ||
message: error.details[0].message | ||
}; | ||
} | ||
// Get relationship model | ||
@@ -18,40 +43,48 @@ const relationshipModel = fnHelper.getModelObject(data.relationship_model); | ||
const repartitionData = await relationshipModel | ||
.aggregate([ | ||
{ | ||
$group: { | ||
_id: `$${data.relationship_model_ref_field}`, | ||
count: data.operation === 'avg' ? { $avg: _value } : { $sum: _value }, | ||
try { | ||
const repartitionData = await relationshipModel | ||
.aggregate([ | ||
{ | ||
$group: { | ||
_id: `$${data.relationship_model_ref_field}`, | ||
count: data.operation === 'avg' ? { $avg: _value } : { $sum: _value }, | ||
} | ||
}, | ||
{ | ||
$project: { | ||
key: '$_id', | ||
value: '$count', | ||
_id: false | ||
} | ||
} | ||
}, | ||
{ | ||
$project: { | ||
key: '$_id', | ||
value: '$count', | ||
_id: false | ||
} | ||
} | ||
]) | ||
.limit(limit) | ||
.sort({ value: -1 }); | ||
]) | ||
.limit(limit) | ||
.sort({ value: -1 }); | ||
const parentIds = repartitionData.map(d => d.key); | ||
const parentData = await currentModel.find({ _id: parentIds }).select(data.field).lean(); | ||
const parentIds = repartitionData.map(d => d.key); | ||
const parentData = await currentModel.find({ _id: parentIds }).select(data.field).lean(); | ||
repartitionData.forEach(d => { | ||
d.item_model = data.model; | ||
d.item_id = d.key; | ||
const parent = parentData.find(p => p._id.toString() === d.key.toString()); | ||
if (parent) { | ||
d.key = parent[data.field]; | ||
} | ||
}); | ||
repartitionData.forEach(d => { | ||
d.item_model = data.model; | ||
d.item_id = d.key; | ||
const parent = parentData.find(p => p._id.toString() === d.key.toString()); | ||
if (parent) { | ||
d.key = parent[data.field]; | ||
} | ||
}); | ||
return { | ||
success: true, | ||
data: { | ||
config: null, | ||
data: repartitionData | ||
} | ||
}; | ||
return { | ||
success: true, | ||
data: { | ||
config: null, | ||
data: repartitionData | ||
} | ||
}; | ||
} | ||
catch(e) { | ||
return { | ||
success: false, | ||
message: e.message | ||
}; | ||
} | ||
}; |
const Joi = require('@hapi/joi'); | ||
const _ = require('lodash'); | ||
const moment = require('moment'); | ||
const fnHelper = require('../helpers/functions'); | ||
module.exports = async (currentModel, data) => { | ||
if (!['day', 'week', 'month', 'year'].includes(data.timeframe)) { | ||
const paramsSchema = Joi.object({ | ||
type: Joi.string().required(), | ||
model: Joi.string().required(), | ||
operation: Joi.string().required(), | ||
group_by: Joi.string().required(), | ||
timeframe: Joi.string().required().valid('day', 'week', 'month', 'year'), | ||
field: Joi.alternatives().conditional('operation', { | ||
not: 'count', | ||
then: Joi.string().required(), | ||
otherwise: Joi.string() | ||
}), | ||
limit: Joi.number().optional(), | ||
date_from: Joi.date().optional(), | ||
date_to: Joi.date().optional() | ||
}); | ||
// Validate params | ||
const { error } = paramsSchema.validate(data); | ||
if (error) { | ||
return { | ||
success: false, | ||
message: 'Invalid timeframe' | ||
message: error.details[0].message | ||
}; | ||
@@ -15,120 +35,88 @@ } | ||
// To set the max date | ||
const toDate = data.to ? moment(data.to) : moment(); | ||
let matchReq = {}; | ||
let groupFormat = ''; | ||
if (data.date_from) { | ||
matchReq['$gte'] = new Date(moment(data.date_from)); | ||
} | ||
if (data.date_to) { | ||
matchReq['$lt'] = new Date(moment(data.date_to)); | ||
} | ||
// Day timeframe | ||
if (data.timeframe === 'day') { | ||
const startOfCurrentDay = toDate.startOf('day'); | ||
matchReq = { | ||
'$gte': new Date(startOfCurrentDay.clone().subtract(30, 'day').startOf('day').format()), | ||
'$lt': new Date(startOfCurrentDay.format()) | ||
}; | ||
groupFormat = '%Y-%m-%d'; | ||
groupFormat = '%Y-%m-%d 00:00:00'; | ||
} | ||
// Week timeframe | ||
else if (data.timeframe === 'week') { | ||
const startOfCurrentWeek = toDate.startOf('week'); | ||
matchReq = { | ||
'$gte': new Date(startOfCurrentWeek.clone().subtract(26, 'week').startOf('week').format()), | ||
'$lt': new Date(startOfCurrentWeek.format()) | ||
}; | ||
groupFormat = '%V'; | ||
groupFormat = '%Y-%V'; | ||
} | ||
// Month timeframe | ||
else if (data.timeframe === 'month') { | ||
const startOfCurrentMonth = toDate.startOf('month'); | ||
matchReq = { | ||
'$gte': new Date(startOfCurrentMonth.clone().subtract(12, 'month').startOf('month').format()), | ||
'$lt': new Date(startOfCurrentMonth.format()) | ||
}; | ||
groupFormat = '%m'; | ||
groupFormat = '%Y-%m-01 00:00:00'; | ||
} | ||
// Year timeframe | ||
else if (data.timeframe === 'year') { | ||
const startOfCurrentYear = toDate.startOf('year'); | ||
matchReq = { | ||
'$gte': new Date(startOfCurrentYear.clone().subtract(8, 'year').startOf('year').format()), | ||
'$lt': new Date(startOfCurrentYear.format()) | ||
}; | ||
groupFormat = '%Y'; | ||
groupFormat = '%Y-01-01 00:00:00'; | ||
} | ||
if (!groupFormat) { | ||
return res.status(403).json({ message: 'Invalid request' }); | ||
return { | ||
success: false, | ||
message: 'Invalid request' | ||
}; | ||
} | ||
const repartitionData = await currentModel | ||
.aggregate([ | ||
{ | ||
$match: { | ||
[data.group_by]: matchReq | ||
let repartitionData; | ||
try { | ||
repartitionData = await currentModel | ||
.aggregate([ | ||
{ | ||
$match: Object.keys(matchReq).length > 0 ? { | ||
[data.group_by]: matchReq | ||
} : {} | ||
}, | ||
{ | ||
$group: { | ||
_id: { $dateToString: { format: groupFormat, date: `$${data.group_by}` } }, | ||
count: { $sum: toSum } | ||
} | ||
}, | ||
{ | ||
$project: { | ||
key: '$_id', | ||
value: '$count', | ||
_id: false | ||
} | ||
} | ||
}, | ||
{ | ||
$group: { | ||
_id: { $dateToString: { format: groupFormat, date: `$${data.group_by}` } }, | ||
count: { $sum: toSum } | ||
} | ||
}, | ||
{ | ||
$project: { | ||
key: '$_id', | ||
value: '$count', | ||
_id: false | ||
} | ||
} | ||
]); | ||
]); | ||
} | ||
catch(e) { | ||
return { | ||
success: false, | ||
message: e.message | ||
}; | ||
} | ||
const formattedData = []; | ||
if (repartitionData && repartitionData.length > 0) { | ||
// Get min & max date in the results | ||
const momentFormat = data.timeframe === 'week' ? 'YYYY-WW' : 'YYYY-MM-DD HH:mm:ss'; | ||
const unixRange = repartitionData.map(data => moment(data.key, momentFormat)); | ||
const min = _.min(unixRange).clone(); | ||
const max = _.max(unixRange).clone(); | ||
// Day timeframe | ||
if (data.timeframe === 'day') { | ||
for (let i = 1; i <= 30; i++) { | ||
const currentDate = toDate.clone().subtract(i, 'day').startOf('day'); | ||
const countForTheTimeframe = _.find(repartitionData, { key: currentDate.format('YYYY-MM-DD') }); | ||
let currentDate = min; | ||
while (currentDate.isSameOrBefore(max)) { | ||
const countForTheTimeframe = repartitionData.find(d => moment(d.key, momentFormat).isSame(currentDate, data.timeframe)); | ||
const value = countForTheTimeframe ? fnHelper.toFixedIfNecessary(countForTheTimeframe.value, 2) : 0; | ||
formattedData.push({ | ||
key: currentDate.format('DD/MM'), | ||
value: countForTheTimeframe ? countForTheTimeframe.value : 0 | ||
key: currentDate.format('YYYY-MM-DD'), | ||
value | ||
}); | ||
currentDate.add(1, data.timeframe).startOf('day'); | ||
} | ||
} | ||
// Week timeframe | ||
else if (data.timeframe === 'week') { | ||
for (let i = 1; i <= 26; i++) { | ||
const currentWeek = toDate.clone().subtract(i, 'week').startOf('week'); | ||
const countForTheTimeframe = _.find(repartitionData, { key: currentWeek.format('WW') }); | ||
formattedData.push({ | ||
key: currentWeek.startOf('week').format('DD/MM'), | ||
value: countForTheTimeframe ? countForTheTimeframe.value : 0 | ||
}); | ||
} | ||
} | ||
// Month timeframe | ||
else if (data.timeframe === 'month') { | ||
for (let i = 1; i <= 12; i++) { | ||
const currentMonth = toDate.clone().subtract(i, 'month').startOf('month'); | ||
const countForTheTimeframe = _.find(repartitionData, { key: currentMonth.format('MM') }); | ||
formattedData.push({ | ||
key: currentMonth.startOf('month').format('MMM'), | ||
value: countForTheTimeframe ? countForTheTimeframe.value : 0 | ||
}); | ||
} | ||
} | ||
// Year timeframe | ||
else if (data.timeframe === 'year') { | ||
for (let i = 1; i <= 8; i++) { | ||
const currentYear = toDate.clone().subtract(i, 'year').startOf('year'); | ||
const countForTheTimeframe = _.find(repartitionData, { key: currentYear.format('YYYY') }); | ||
formattedData.push({ | ||
key: currentYear.startOf('year').format('YYYY'), | ||
value: countForTheTimeframe ? countForTheTimeframe.value : 0 | ||
}); | ||
} | ||
} | ||
const formattedDataOrdered = formattedData.reverse(); | ||
const chartConfig = { | ||
@@ -139,4 +127,3 @@ xaxis: [ | ||
yaxis: [ | ||
{ dataKey: 'value' }, | ||
// { dataKey: 'test', orientation: 'right' } | ||
{ dataKey: 'value' } | ||
] | ||
@@ -149,5 +136,5 @@ }; | ||
config: chartConfig, | ||
data: formattedDataOrdered | ||
data: formattedData | ||
} | ||
}; | ||
}; | ||
}; |
@@ -0,45 +1,73 @@ | ||
const Joi = require('@hapi/joi'); | ||
module.exports = async (currentModel, data) => { | ||
if (data.operation === 'sum') { | ||
const sumData = await currentModel | ||
.aggregate([{ | ||
$group: { | ||
_id: `$${data.group_by}`, | ||
count: { $sum: `$${data.field}` }, | ||
} | ||
}]); | ||
const paramsSchema = Joi.object({ | ||
type: Joi.string().required(), | ||
model: Joi.string().required(), | ||
operation: Joi.string().required(), | ||
field: Joi.alternatives().conditional('operation', { | ||
not: 'count', | ||
then: Joi.string().required(), | ||
otherwise: Joi.string() | ||
}) | ||
}); | ||
if (!sumData || !sumData[0] || typeof sumData[0].count !== 'number') { | ||
return res.status(403).json(); | ||
} | ||
// Validate params | ||
const { error } = paramsSchema.validate(data); | ||
if (error) { | ||
return { | ||
success: true, | ||
data: { | ||
config: null, | ||
data: sumData[0].count | ||
} | ||
success: false, | ||
message: error.details[0].message | ||
}; | ||
} | ||
else if (data.operation === 'avg') { | ||
const avgData = await currentModel | ||
.aggregate([{ | ||
$group: { | ||
_id: `$${data.group_by}`, | ||
avg: { $avg: `$${data.field}` }, | ||
try { | ||
if (data.operation === 'sum') { | ||
const sumData = await currentModel | ||
.aggregate([{ | ||
$group: { | ||
_id: `$${data.group_by}`, | ||
count: { | ||
$sum: `$${data.field}` | ||
} | ||
} | ||
}]); | ||
if (!sumData || !sumData[0] || typeof sumData[0].count !== 'number') { | ||
return res.status(403).json(); | ||
} | ||
return { | ||
success: true, | ||
data: { | ||
config: null, | ||
data: sumData[0].count | ||
} | ||
}]); | ||
}; | ||
} | ||
else if (data.operation === 'avg') { | ||
const avgData = await currentModel | ||
.aggregate([{ | ||
$group: { | ||
_id: `$${data.group_by}`, | ||
avg: { | ||
$avg: `$${data.field}` | ||
} | ||
} | ||
}]); | ||
if (!avgData || !avgData[0] || typeof avgData[0].avg !== 'number') { | ||
return res.status(403).json(); | ||
if (!avgData || !avgData[0] || typeof avgData[0].avg !== 'number') { | ||
return res.status(403).json(); | ||
} | ||
return { | ||
success: true, | ||
data: { | ||
config: null, | ||
data: avgData[0].avg | ||
} | ||
}; | ||
} | ||
return { | ||
success: true, | ||
data: { | ||
config: null, | ||
data: avgData[0].avg | ||
} | ||
}; | ||
} | ||
else { | ||
// Simple count | ||
const dataCount = await currentModel.countDocuments({}); | ||
@@ -55,2 +83,8 @@ | ||
} | ||
catch(e) { | ||
return { | ||
success: false, | ||
message: e.message | ||
}; | ||
} | ||
}; |
@@ -223,2 +223,6 @@ const mongoose = require('mongoose'); | ||
module.exports.toFixedIfNecessary = (value, dp) => { | ||
return +parseFloat(value).toFixed(dp); | ||
}; | ||
module.exports.constructQuery = jsonQuery => { | ||
@@ -225,0 +229,0 @@ if (jsonQuery.operator && jsonQuery.list && jsonQuery.list.length) { |
38147
1145
6
+ Added@hapi/joi@^17.1.1
+ Added@hapi/address@4.1.0(transitive)
+ Added@hapi/formula@2.0.0(transitive)
+ Added@hapi/hoek@9.3.0(transitive)
+ Added@hapi/joi@17.1.1(transitive)
+ Added@hapi/pinpoint@2.0.1(transitive)
+ Added@hapi/topo@5.1.0(transitive)