added filters
This commit is contained in:
@ -44,7 +44,7 @@ router.get('/samples', async (req, res, next) => {
|
||||
|
||||
if (filters.sort[0].indexOf('measurements.') >= 0) { // sorting with measurements as starting collection
|
||||
collection = MeasurementModel;
|
||||
const measurementName = filters.sort[0].replace('measurements.', '');
|
||||
const [,measurementName, measurementParam] = filters.sort[0].split('.');
|
||||
const measurementTemplate = await MeasurementTemplateModel.findOne({name: measurementName}).lean().exec().catch(err => {next(err);});
|
||||
if (measurementTemplate instanceof Error) return;
|
||||
if (!measurementTemplate) {
|
||||
@ -57,11 +57,14 @@ router.get('/samples', async (req, res, next) => {
|
||||
if (!fromSample) {
|
||||
return res.status(400).json({status: 'Invalid body format', details: 'from-id not found'});
|
||||
}
|
||||
sortStartValue = fromSample.values[measurementTemplate.parameters[0].name];
|
||||
sortStartValue = fromSample.values[measurementParam];
|
||||
}
|
||||
query[0].$match.$and.push({measurement_template: mongoose.Types.ObjectId(measurementTemplate._id)}); // find measurements to sort
|
||||
if (filters.filters.find(e => e.field === filters.sort[0])) { // sorted measurement should also be filtered
|
||||
query[0].$match.$and.push(...filterQueries(filters.filters.find(e => e.field === filters.sort[0])));
|
||||
}
|
||||
query.push(
|
||||
sortQuery(query, filters, ['values.' + measurementTemplate.parameters[0].name, 'sample_id'], sortStartValue), // sort measurements
|
||||
sortQuery(query, filters, ['values.' + measurementParam, 'sample_id'], sortStartValue), // sort measurements
|
||||
{$replaceRoot: {newRoot: {measurement: '$$ROOT'}}}, // fetch samples and restructure them to fit sample structure
|
||||
{$lookup: {from: 'samples', localField: 'measurement.sample_id', foreignField: '_id', as: 'sample'}},
|
||||
{$match: statusQuery(filters, 'sample.status')} // filter out wrong status once samples were added
|
||||
@ -71,12 +74,13 @@ router.get('/samples', async (req, res, next) => {
|
||||
{$set: {['sample.' + measurementName]: '$measurement.values'}}, // more restructuring
|
||||
{$replaceRoot: {newRoot: {$mergeObjects: [{$arrayElemAt: ['$sample', 0]}, {}]}}}
|
||||
);
|
||||
|
||||
addFilterQueries(query, filters.filters.filter(e => sampleKeys.indexOf(e.field) >= 0)); // sample filters
|
||||
}
|
||||
else { // sorting with samples as starting collection
|
||||
collection = SampleModel;
|
||||
// filter for status
|
||||
query[0].$match.$and.push(statusQuery(filters, 'status'));
|
||||
addFilterQueries(query, filters.filters.filter(e => sampleKeys.indexOf(e.field) >= 0)); // sample filters
|
||||
|
||||
// differentiate by sort key to do sorting, skip and limit as early as possible
|
||||
if (sampleKeys.indexOf(filters.sort[0]) >= 0) { // sorting for sample keys
|
||||
@ -90,6 +94,7 @@ router.get('/samples', async (req, res, next) => {
|
||||
sortStartValue = fromSample[filters.sort[0]];
|
||||
}
|
||||
query.push(sortQuery(query, filters, [filters.sort[0], '_id'], sortStartValue));
|
||||
// material filters
|
||||
addSkipLimit(query, filters);
|
||||
}
|
||||
else { // sorting for material keys
|
||||
@ -130,41 +135,54 @@ router.get('/samples', async (req, res, next) => {
|
||||
}
|
||||
}
|
||||
|
||||
const fieldsNoSort = filters.fields.filter(e => e !== filters.sort[0]); // sort field was definitely added already, exclude from further field operations
|
||||
if (fieldsNoSort.find(e => /material\./.test(e))) { // add material fields
|
||||
const fieldsToAdd = [
|
||||
...filters.fields,
|
||||
...filters.filters.map(e => e.field) // add filter fields in case they were not specified to display
|
||||
].filter(e => e !== filters.sort[0]) // sort field was definitely added already, exclude from further field operations
|
||||
.filter((e, i, self) => self.indexOf(e) === i); // remove duplicates
|
||||
if (fieldsToAdd.find(e => /material\./.test(e))) { // add material fields
|
||||
query.push(
|
||||
{$lookup: {from: 'materials', localField: 'material_id', foreignField: '_id', as: 'material'}},
|
||||
{$set: {material: { $arrayElemAt: ['$material', 0]}}}
|
||||
);
|
||||
}
|
||||
if (fieldsNoSort.indexOf('material.supplier') >= 0) { // add supplier if needed
|
||||
if (fieldsToAdd.indexOf('material.supplier') >= 0) { // add supplier if needed
|
||||
query.push(
|
||||
{$lookup: { from: 'material_suppliers', localField: 'material.supplier_id', foreignField: '_id', as: 'material.supplier'}},
|
||||
{$set: {'material.supplier': {$arrayElemAt: ['$material.supplier.name', 0]}}}
|
||||
);
|
||||
}
|
||||
if (fieldsNoSort.indexOf('material.group') >= 0) { // add group if needed
|
||||
if (fieldsToAdd.indexOf('material.group') >= 0) { // add group if needed
|
||||
query.push(
|
||||
{$lookup: { from: 'material_groups', localField: 'material.group_id', foreignField: '_id', as: 'material.group' }},
|
||||
{$set: {'material.group': { $arrayElemAt: ['$material.group.name', 0]}}}
|
||||
);
|
||||
}
|
||||
if (fieldsNoSort.indexOf('material.number') >= 0) { // add material number if needed
|
||||
if (fieldsToAdd.indexOf('material.number') >= 0) { // add material number if needed
|
||||
query.push(
|
||||
{$set: {'material.number': { $arrayElemAt: ['$material.numbers.number', {$indexOfArray: ['$material.numbers.color', '$color']}]}}}
|
||||
);
|
||||
}
|
||||
|
||||
let measurementFields = filters.fields.filter(e => /measurements\./.test(e)).map(e => e.replace('measurements.', ''));
|
||||
console.log(fieldsNoSort);
|
||||
console.log(measurementFields);
|
||||
if (fieldsNoSort.find(e => /measurements\./.test(e))) { // add measurement fields
|
||||
query.push({$lookup: {from: 'measurements', localField: '_id', foreignField: 'sample_id', as: 'measurements'}});
|
||||
addFilterQueries(query, filters.filters.filter(e => /material\./.test(e.field))); // material filters
|
||||
|
||||
let measurementFields = fieldsToAdd.filter(e => /measurements\./.test(e)).map(e => e.split('.')[1]).filter((e, i, self) => self.indexOf(e) === i); // filter measurement names and remove duplicates from parameters
|
||||
if (fieldsToAdd.find(e => /measurements\./.test(e))) { // add measurement fields
|
||||
const measurementTemplates = await MeasurementTemplateModel.find({$or: measurementFields.filter(e => e !== filters.sort[0].replace('measurements.', '')).map(e => {return {name: e}})}).lean().exec().catch(err => {next(err);});
|
||||
if (measurementTemplates instanceof Error) return;
|
||||
if (measurementTemplates.length < measurementFields.length) {
|
||||
return res.status(400).json({status: 'Invalid body format', details: 'Measurement key not found'});
|
||||
}
|
||||
if (fieldsToAdd.find(e => e === 'measurements.spectrum')) { // use different lookup methods with and without spectrum for the best performance
|
||||
query.push({$lookup: {from: 'measurements', localField: '_id', foreignField: 'sample_id', as: 'measurements'}});
|
||||
}
|
||||
else {
|
||||
query.push({$lookup: {
|
||||
from: 'measurements', let: {sId: '$_id'},
|
||||
pipeline: [{$match: {$expr: {$and: [{$eq: ['$sample_id', '$$sId']}, {$in: ['$measurement_template', measurementTemplates.map(e => mongoose.Types.ObjectId(e._id))]}]}}}],
|
||||
as: 'measurements'
|
||||
}});
|
||||
}
|
||||
measurementTemplates.filter(e => e.name !== 'spectrum').forEach(template => { // TODO: hard coded dpt for special treatment, change later
|
||||
query.push({$set: {[template.name]: {$let: { // add measurements as property [template.name], if one result, array is reduced to direct values
|
||||
vars: {arr: {$filter: {input: '$measurements', cond: {$eq: ['$$this.measurement_template', mongoose.Types.ObjectId(template._id)]}}}},
|
||||
@ -180,6 +198,7 @@ router.get('/samples', async (req, res, next) => {
|
||||
}
|
||||
query.push({$unset: 'measurements'});
|
||||
}
|
||||
addFilterQueries(query, filters.filters.filter(e => /measurements\./.test(e.field)).map(e => {e.field = e.field.replace('measurements.', ''); return e; })); // measurement filters
|
||||
|
||||
const projection = filters.fields.map(e => e.replace('measurements.', '')).reduce((s, e) => {s[e] = true; return s; }, {});
|
||||
if (filters.fields.indexOf('added') >= 0) { // add added date
|
||||
@ -601,4 +620,14 @@ function statusQuery(filters, field) {
|
||||
else { // default
|
||||
return {[field]: globals.status.validated};
|
||||
}
|
||||
}
|
||||
|
||||
function addFilterQueries (query, filters) { // returns array of match queries from given filters
|
||||
if (filters.length) {
|
||||
query.push({$match: {$and: 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
|
||||
}
|
Reference in New Issue
Block a user