switched to aggregation, included material sort keys
This commit is contained in:
		@@ -230,6 +230,20 @@ describe('/sample', () => {
 | 
				
			|||||||
        done();
 | 
					        done();
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					    it('sorts the samples correctly for material keys', done => {
 | 
				
			||||||
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
 | 
					        method: 'get',
 | 
				
			||||||
 | 
					        url: '/samples?status=all&sort=material.name-desc',
 | 
				
			||||||
 | 
					        auth: {basic: 'janedoe'},
 | 
				
			||||||
 | 
					        httpStatus: 200
 | 
				
			||||||
 | 
					      }).end((err, res) => {
 | 
				
			||||||
 | 
					        if (err) return done(err);
 | 
				
			||||||
 | 
					        should(res.body[0]).have.property('_id', '400000000000000000000002');
 | 
				
			||||||
 | 
					        should(res.body[1]).have.property('_id', '400000000000000000000006');
 | 
				
			||||||
 | 
					        should(res.body[2]).have.property('_id', '400000000000000000000001');
 | 
				
			||||||
 | 
					        done();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
    it('rejects a negative page size', done => {
 | 
					    it('rejects a negative page size', done => {
 | 
				
			||||||
      TestHelper.request(server, done, {
 | 
					      TestHelper.request(server, done, {
 | 
				
			||||||
        method: 'get',
 | 
					        method: 'get',
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,65 +25,69 @@ router.get('/samples', async (req, res, next) => {
 | 
				
			|||||||
  const {error, value: filters} = SampleValidate.query(req.query);
 | 
					  const {error, value: filters} = SampleValidate.query(req.query);
 | 
				
			||||||
  if (error) return res400(error, res);
 | 
					  if (error) return res400(error, res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  let status;
 | 
					  const query = [];
 | 
				
			||||||
 | 
					  query.push({$match: {$and: []}});
 | 
				
			||||||
  if (filters.hasOwnProperty('status')) {
 | 
					  if (filters.hasOwnProperty('status')) {
 | 
				
			||||||
    if(filters.status === 'all') {
 | 
					    if(filters.status === 'all') {
 | 
				
			||||||
      status = {$or: [{status: globals.status.validated}, {status: globals.status.new}]}
 | 
					      query[0].$match.$and.push({$or: [{status: globals.status.validated}, {status: globals.status.new}]});
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
      status = {status: globals.status[filters.status]};
 | 
					      query[0].$match.$and.push({status: globals.status[filters.status]});
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  else {  // default
 | 
					  else {  // default
 | 
				
			||||||
    status = {status: globals.status.validated};
 | 
					    query[0].$match.$and.push({status: globals.status.validated});
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
  const sort = [];
 | 
					 | 
				
			||||||
  let paging = {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // sorting
 | 
					  // sorting
 | 
				
			||||||
  filters.sort = filters.sort.split('-');
 | 
					  filters.sort = filters.sort.split('-');
 | 
				
			||||||
  filters.sort[0] = filters.sort[0] === 'added' ? '_id' : filters.sort[0];  // route added sorting criteria to _id
 | 
					  filters.sort[0] = filters.sort[0] === 'added' ? '_id' : filters.sort[0];  // route added sorting criteria to _id
 | 
				
			||||||
  filters.sort[1] = filters.sort[1] === 'desc' ? -1 : 1;
 | 
					  filters.sort[1] = filters.sort[1] === 'desc' ? -1 : 1;
 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!filters['to-page']) {  // set to-page default
 | 
					  if (!filters['to-page']) {  // set to-page default
 | 
				
			||||||
    filters['to-page'] = 0;
 | 
					    filters['to-page'] = 0;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (filters.sort[0].indexOf('material.') >= 0) {  // need to populate materials, material supplier and group
 | 
				
			||||||
 | 
					    query.push(
 | 
				
			||||||
 | 
					      {$lookup: {from: 'materials', localField: 'material_id', foreignField: '_id', as: 'material'}},
 | 
				
			||||||
 | 
					      {$set: {material: { $arrayElemAt: ['$material', 0]}}},
 | 
				
			||||||
 | 
					      {$lookup: { from: 'material_groups', localField: 'material.group_id', foreignField: '_id', as: 'material.group' }},
 | 
				
			||||||
 | 
					      {$set: {'material.group': { $arrayElemAt: ['$material.group.name', 0]}}},
 | 
				
			||||||
 | 
					      {$lookup: { from: 'material_suppliers', localField: 'material.supplier_id', foreignField: '_id', as: 'material.supplier'}},
 | 
				
			||||||
 | 
					      {$set: {'material.supplier': {$arrayElemAt: ['$material.supplier.name', 0]}}}
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (filters['from-id']) {  // from-id specified
 | 
					  if (filters['from-id']) {  // from-id specified
 | 
				
			||||||
    const fromSample = SampleValidate.output(await SampleModel.findById(filters['from-id']).lean().exec().catch(err => {next(err);}));
 | 
					    const fromSample = await SampleModel.findById(filters['from-id']).lean().exec().catch(err => {next(err);});
 | 
				
			||||||
    if (fromSample instanceof Error) return;
 | 
					    if (fromSample instanceof Error) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((filters['to-page'] === 0 && filters.sort[1] === 1) || (filters.sort[1] * filters['to-page'] > 0)) {  // asc
 | 
					    if ((filters['to-page'] === 0 && filters.sort[1] === 1) || (filters.sort[1] * filters['to-page'] > 0)) {  // asc
 | 
				
			||||||
      paging = {$or: [{[filters.sort[0]]: {$gt: fromSample[filters.sort[0]]}}, {$and: [{[filters.sort[0]]: fromSample[filters.sort[0]]}, {_id: {$gte: mongoose.Types.ObjectId(filters['from-id'])}}]}]};
 | 
					      query[0].$match.$and.push({$or: [{[filters.sort[0]]: {$gt: fromSample[filters.sort[0]]}}, {$and: [{[filters.sort[0]]: fromSample[filters.sort[0]]}, {_id: {$gte: new mongoose.Types.ObjectId(filters['from-id'])}}]}]});
 | 
				
			||||||
      sort.push([filters.sort[0], 1]);
 | 
					      query.push({$sort: {[filters.sort[0]]: 1, _id: 1}});
 | 
				
			||||||
      sort.push(['_id', 1]);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    else {
 | 
					    else {
 | 
				
			||||||
      paging = {$or: [{[filters.sort[0]]: {$lt: fromSample[filters.sort[0]]}}, {$and: [{[filters.sort[0]]: fromSample[filters.sort[0]]}, {_id: {$lte: mongoose.Types.ObjectId(filters['from-id'])}}]}]};
 | 
					      query[0].$match.$and.push({$or: [{[filters.sort[0]]: {$lt: fromSample[filters.sort[0]]}}, {$and: [{[filters.sort[0]]: fromSample[filters.sort[0]]}, {_id: {$lte: new mongoose.Types.ObjectId(filters['from-id'])}}]}]});
 | 
				
			||||||
      sort.push([filters.sort[0], -1]);
 | 
					      query.push({$sort: {[filters.sort[0]]: -1, _id: -1}});
 | 
				
			||||||
      sort.push(['_id', -1]);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  else {  // sort from beginning
 | 
					  else {  // sort from beginning
 | 
				
			||||||
    sort.push([filters.sort[0], filters.sort[1]]);  // set _id as secondary sort
 | 
					    query.push({$sort: {[filters.sort[0]]: filters.sort[1], '_id': filters.sort[1]}});  // set _id as secondary sort
 | 
				
			||||||
    sort.push(['_id', filters.sort[1]]);  // set _id as secondary sort
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const query = SampleModel.find({$and: [status, paging]});
 | 
					  if (filters.sort[0].indexOf('material.') >= 0) {  // unpopulate materials again
 | 
				
			||||||
 | 
					    query.push({$unset: 'material'});
 | 
				
			||||||
  if (filters['page-size']) {
 | 
					 | 
				
			||||||
    query.limit(filters['page-size']);
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (filters['to-page']) {
 | 
					  if (filters['to-page']) {
 | 
				
			||||||
    query.skip(Math.abs(filters['to-page'] + Number(filters['to-page'] < 0)) * filters['page-size'] + Number(filters['to-page'] < 0));
 | 
					    query.push({$skip: Math.abs(filters['to-page'] + Number(filters['to-page'] < 0)) * filters['page-size'] + Number(filters['to-page'] < 0)})  // number to skip, if going back pages, one page has to be skipped less but on sample more
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  query.sort(sort);
 | 
					  if (filters['page-size']) {
 | 
				
			||||||
 | 
					    query.push({$limit: filters['page-size']});
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  query.lean().exec((err, data) => {
 | 
					  SampleModel.aggregate(query).exec((err, data) => {
 | 
				
			||||||
    if (err) return next(err);
 | 
					    if (err) return next(err);
 | 
				
			||||||
    if (filters['to-page'] < 0) {
 | 
					    if (filters['to-page'] < 0) {
 | 
				
			||||||
      data.reverse();
 | 
					      data.reverse();
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -133,7 +133,7 @@ export default class SampleValidate {
 | 
				
			|||||||
      'from-id': IdValidate.get(),
 | 
					      'from-id': IdValidate.get(),
 | 
				
			||||||
      'to-page': Joi.number().integer(),
 | 
					      'to-page': Joi.number().integer(),
 | 
				
			||||||
      'page-size': Joi.number().integer().min(1),
 | 
					      'page-size': Joi.number().integer().min(1),
 | 
				
			||||||
      sort: Joi.string().pattern(/^(_id|color|number|type|batch|added)-(asc|desc)$/m).default('_id-asc')  // TODO: material keys
 | 
					      sort: Joi.string().pattern(/^(_id|color|number|type|batch|added|material\.name|material\.supplier|material\.group|material\.mineral|material\.glass_fiber|material\.carbon_fiber)-(asc|desc)$/m).default('_id-asc')  // TODO: material keys
 | 
				
			||||||
    }).with('to-page', 'page-size').validate(data);
 | 
					    }).with('to-page', 'page-size').validate(data);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user