implemented added filters
This commit is contained in:
parent
523b2c9b68
commit
758eb0e143
@ -7,7 +7,7 @@ import ChangelogModel from './models/changelog';
|
|||||||
// database urls, prod db url is retrieved automatically
|
// database urls, prod db url is retrieved automatically
|
||||||
const TESTING_URL = 'mongodb://localhost/dfopdb_test';
|
const TESTING_URL = 'mongodb://localhost/dfopdb_test';
|
||||||
const DEV_URL = 'mongodb://localhost/dfopdb';
|
const DEV_URL = 'mongodb://localhost/dfopdb';
|
||||||
const debugging = false;
|
const debugging = true;
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production' && debugging) {
|
if (process.env.NODE_ENV !== 'production' && debugging) {
|
||||||
mongoose.set('debug', true); // enable mongoose debug
|
mongoose.set('debug', true); // enable mongoose debug
|
||||||
|
@ -43,6 +43,54 @@ router.get('/samples', async (req, res, next) => {
|
|||||||
if (!filters['to-page']) { // set to-page default
|
if (!filters['to-page']) { // set to-page default
|
||||||
filters['to-page'] = 0;
|
filters['to-page'] = 0;
|
||||||
}
|
}
|
||||||
|
const addedFilter = filters.filters.find(e => e.field === 'added');
|
||||||
|
if (addedFilter) { // convert added filter to object id
|
||||||
|
filters.filters.splice(filters.filters.findIndex(e => e.field === 'added'), 1);
|
||||||
|
if (addedFilter.mode === 'in') {
|
||||||
|
const v = []; // query value
|
||||||
|
addedFilter.values.forEach(value => {
|
||||||
|
const date = [new Date(value).setHours(0,0,0,0), new Date(value).setHours(23,59,59,999)];
|
||||||
|
v.push({$and: [{ _id: { '$gte': dateToOId(date[0])}}, { _id: { '$lte': dateToOId(date[1])}}]});
|
||||||
|
});
|
||||||
|
filters.filters.push({mode: 'or', field: '_id', values: v});
|
||||||
|
}
|
||||||
|
else if (addedFilter.mode === 'nin') {
|
||||||
|
addedFilter.values = addedFilter.values.sort();
|
||||||
|
const v = []; // query value
|
||||||
|
|
||||||
|
for (let i = 0; i <= addedFilter.values.length; i ++) {
|
||||||
|
v[i] = {$and: []};
|
||||||
|
if (i > 0) {
|
||||||
|
const date = new Date(addedFilter.values[i - 1]).setHours(23,59,59,999);
|
||||||
|
v[i].$and.push({ _id: { '$gt': dateToOId(date)}}) ;
|
||||||
|
}
|
||||||
|
if (i < addedFilter.values.length) {
|
||||||
|
const date = new Date(addedFilter.values[i]).setHours(0,0,0,0);
|
||||||
|
v[i].$and.push({ _id: { '$lt': dateToOId(date)}}) ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filters.filters.push({mode: 'or', field: '_id', values: v});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// start and end of day
|
||||||
|
const date = [new Date(addedFilter.values[0]).setHours(0,0,0,0), new Date(addedFilter.values[0]).setHours(23,59,59,999)];
|
||||||
|
if (addedFilter.mode === 'lt') { // lt start
|
||||||
|
filters.filters.push({mode: 'lt', field: '_id', values: [dateToOId(date[0])]});
|
||||||
|
}
|
||||||
|
if (addedFilter.mode === 'eq' || addedFilter.mode === 'lte') { // lte end
|
||||||
|
filters.filters.push({mode: 'lte', field: '_id', values: [dateToOId(date[1])]});
|
||||||
|
}
|
||||||
|
if (addedFilter.mode === 'gt') { // gt end
|
||||||
|
filters.filters.push({mode: 'gt', field: '_id', values: [dateToOId(date[1])]});
|
||||||
|
}
|
||||||
|
if (addedFilter.mode === 'eq' || addedFilter.mode === 'gte') { // gte start
|
||||||
|
filters.filters.push({mode: 'gte', field: '_id', values: [dateToOId(date[0])]});
|
||||||
|
}
|
||||||
|
if (addedFilter.mode === 'ne') {
|
||||||
|
filters.filters.push({mode: 'or', field: '_id', values: [{ _id: { '$lt': dateToOId(date[0])}}, { _id: { '$gt': dateToOId(date[1])}}]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const sortFilterKeys = filters.filters.map(e => e.field);
|
const sortFilterKeys = filters.filters.map(e => e.field);
|
||||||
|
|
||||||
@ -80,7 +128,6 @@ router.get('/samples', async (req, res, next) => {
|
|||||||
{$addFields: {['sample.' + measurementName]: '$measurement.values'}}, // more restructuring
|
{$addFields: {['sample.' + measurementName]: '$measurement.values'}}, // more restructuring
|
||||||
{$replaceRoot: {newRoot: {$mergeObjects: [{$arrayElemAt: ['$sample', 0]}, {}]}}}
|
{$replaceRoot: {newRoot: {$mergeObjects: [{$arrayElemAt: ['$sample', 0]}, {}]}}}
|
||||||
);
|
);
|
||||||
addFilterQueries(queryPtr, filters.filters.filter(e => sampleKeys.indexOf(e.field) >= 0)); // sample filters
|
|
||||||
}
|
}
|
||||||
else { // sorting with samples as starting collection
|
else { // sorting with samples as starting collection
|
||||||
collection = SampleModel;
|
collection = SampleModel;
|
||||||
@ -568,13 +615,23 @@ module.exports = router;
|
|||||||
|
|
||||||
async function numberGenerate (sample, req, res, next) { // generate number in format Location32, returns false on error
|
async function numberGenerate (sample, req, res, next) { // generate number in format Location32, returns false on error
|
||||||
const sampleData = await SampleModel
|
const sampleData = await SampleModel
|
||||||
.findOne({number: new RegExp('^' + req.authDetails.location + '[0-9]+$', 'm')})
|
// .findOne({number: new RegExp('^' + req.authDetails.location + '[0-9]+$', 'm')})
|
||||||
.sort({number: -1})
|
// .sort({number: -1})
|
||||||
.lean()
|
// .lean()
|
||||||
|
.aggregate([
|
||||||
|
{$match: {number: new RegExp('^' + 'Rng' + '[0-9]+$', 'm')}},
|
||||||
|
// {$addFields: {number2: {$toDecimal: {$arrayElemAt: [{$split: [{$arrayElemAt: [{$split: ['$number', 'Rng']}, 1]}, '_']}, 0]}}}}, // not working with MongoDb 3.6
|
||||||
|
{$addFields: {sortNumber: {$let: {
|
||||||
|
vars: {tmp: {$concat: ['000000000000000000000000000000', {$arrayElemAt: [{$split: [{$arrayElemAt: [{$split: ['$number', 'Rng']}, 1]}, '_']}, 0]}]}},
|
||||||
|
in: {$substrCP: ['$$tmp', {$subtract: [{$strLenCP: '$$tmp'}, 30]}, {$strLenCP: '$$tmp'}]}
|
||||||
|
}}}},
|
||||||
|
{$sort: {sortNumber: -1}},
|
||||||
|
{$limit: 1}
|
||||||
|
])
|
||||||
.exec()
|
.exec()
|
||||||
.catch(err => next(err));
|
.catch(err => next(err));
|
||||||
if (sampleData instanceof Error) return false;
|
if (sampleData instanceof Error) return false;
|
||||||
return req.authDetails.location + (sampleData ? Number(sampleData.number.replace(/[^0-9]+/g, '')) + 1 : 1);
|
return req.authDetails.location + (sampleData[0] ? Number(sampleData[0].number.replace(/[^0-9]+/g, '')) + 1 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function numberCheck(sample, res, next) {
|
async function numberCheck(sample, res, next) {
|
||||||
@ -707,5 +764,16 @@ function addFilterQueries (queryPtr, filters) { // returns array of match queri
|
|||||||
}
|
}
|
||||||
|
|
||||||
function filterQueries (filters) {
|
function filterQueries (filters) {
|
||||||
return filters.map(e => ({[e.field]: {['$' + e.mode]: (e.mode.indexOf('in') >= 0 ? e.values : e.values[0])}})) // add filter criteria as {field: {$mode: value}}, only use first value when mode is not in/nin
|
return filters.map(e => {
|
||||||
|
if (e.mode === 'or') { // allow or queries (needed for $ne added)
|
||||||
|
return {['$' + e.mode]: e.values};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return {[e.field]: {['$' + e.mode]: (e.mode.indexOf('in') >= 0 ? e.values : e.values[0])}}; // add filter criteria as {field: {$mode: value}}, only use first value when mode is not in/nin
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function dateToOId (date) { // convert date to ObjectId
|
||||||
|
return mongoose.Types.ObjectId(Math.floor(date / 1000).toString(16) + '0000000000000000');
|
||||||
}
|
}
|
@ -175,7 +175,7 @@ export default class SampleValidate {
|
|||||||
let validator;
|
let validator;
|
||||||
let field = data.filters[i].field
|
let field = data.filters[i].field
|
||||||
if (/material\./.test(field)) { // select right validation model
|
if (/material\./.test(field)) { // select right validation model
|
||||||
validator = MaterialValidate.outputV();
|
validator = MaterialValidate.outputV().append({number: Joi.string().max(128).allow('')});
|
||||||
field = field.replace('material.', '');
|
field = field.replace('material.', '');
|
||||||
}
|
}
|
||||||
else if (/measurements\./.test(field)) {
|
else if (/measurements\./.test(field)) {
|
||||||
@ -195,7 +195,7 @@ export default class SampleValidate {
|
|||||||
validator = Joi.object(this.sample);
|
validator = Joi.object(this.sample);
|
||||||
}
|
}
|
||||||
const {value, error} = validator.validate({[field]: e});
|
const {value, error} = validator.validate({[field]: e});
|
||||||
if (error) throw error; // reject invalid values
|
if (error) throw error; // reject invalid values // TODO: return exact error description, handle in frontend filters
|
||||||
return value[field];
|
return value[field];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -215,7 +215,7 @@ export default class SampleValidate {
|
|||||||
filters: Joi.array().items(Joi.object({
|
filters: Joi.array().items(Joi.object({
|
||||||
mode: Joi.string().valid('eq', 'ne', 'lt', 'lte', 'gt', 'gte', 'in', 'nin'),
|
mode: Joi.string().valid('eq', 'ne', 'lt', 'lte', 'gt', 'gte', 'in', 'nin'),
|
||||||
field: Joi.string().pattern(new RegExp('^(' + this.fieldKeys.join('|').replace(/\./g, '\\.').replace(/\*/g, '.+') + ')$', 'm')),
|
field: Joi.string().pattern(new RegExp('^(' + this.fieldKeys.join('|').replace(/\./g, '\\.').replace(/\*/g, '.+') + ')$', 'm')),
|
||||||
values: Joi.array().items(Joi.alternatives().try(Joi.string().max(128), Joi.number(), Joi.boolean())).min(1)
|
values: Joi.array().items(Joi.alternatives().try(Joi.string().max(128), Joi.number(), Joi.boolean(), Joi.date().iso())).min(1)
|
||||||
})).default([])
|
})).default([])
|
||||||
}).with('to-page', 'page-size').validate(data);
|
}).with('to-page', 'page-size').validate(data);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user