Issue
We are trying to build a function in NodeJS that allows us to use that function with find or aggregrate parameters and returns the result.
The find option works fine, also the limit and offset does. But the aggregation will not work. We get the error
Arguments must be aggregate pipeline operators
when we call the function.
The models looks like (I have removed some fields)
product.model.js
var Product = new mongoose.Schema({
name: { //obsolete
type: String,
required: true
},
nameSlug: { //obsolete
type: String,
required: true
},
views: {
type: Number,
min: 0,
default: 0,
required: true
},
waterproofLevel: {
type: Number,
min: 0,
max: 3000,
default: 0,
required: true
},
productCollection: {
type: String
},
male: {
type: Boolean,
default: true,
required: true
},
female: {
type: Boolean,
default: false,
required: true
},
kids: Boolean,
isBestseller: {
type: Boolean,
default: false,
required: true
},
suggestedRetailPrice: {
type: Number,
required: true
},
productNumber: {
type: String,
required: true
},
ean: {
type: String,
minlength: 5,
maxlength: 13,
validate: validators.isNumeric({message: 'Invalid EAN: EAN codes consist of 13 digits'}),
required: true
},
brand: [{
_id: false,
name: {
type: String,
required: true
},
image: [Image]
}],
images: [Image],
});
getProducts function
module.exports.getProducts = function(req, res) {
console.log('[getProducts controller]');
// default values, because offset and limit are required
var filterBy, sortBy, offset, limit, aggregate;
if(req.query) {
if(typeof req.query === 'string') {
req.query = JSON.parse(req.query);
}
if(req.query.offset && !isNaN(parseInt(req.query.offset))) {
offset = parseInt(req.query.offset);
delete req.query.offset;
}
if(req.query.limit && !isNaN(parseInt(req.query.limit))) {
limit = parseInt(req.query.limit);
delete req.query.limit;
}
// if any filters are provided in the URL, parse them and add to the filtering or aggregate params object.
if(req.query.aggregate) {
aggregate = req.query.aggregate;
}else if(req.query.filter) {
filterBy = filter(req.query.filter);
}
// if any sorting parameters are provided in the URL, parse them and add to the Mongoose sorting object.
if(req.query.sort) {
sortBy = sort(req.query.sort);
}
if(req.query.lng && req.query.lat) {
// TODO find products close to the given coordinates.
}
}
if(aggregate){
console.log("aggregate", aggregate);
var query = Product.aggregate(aggregate).allowDiskUse(true);
}else{
var query = Product.find(filterBy);
}
query.skip(offset).limit(limit).exec(function(err, products) {
var status, response;
if(err) {
status = 500;
response = {message: 'Internal server error. ' + err};
} else if(!products || products.length == 0) {
status = 404;
response = {message: 'No products found with the given search criteria. '};
} else {
status = 200;
response = {message: 'OK', products};
}
console.log(status + ' ' + response.message);
res.status(status).json(response);
});
};
The products collection currently has around the 2500 products. So, I read on a other question about the allowDiskUsage(true)
function.
We call the function with our $api service, which is a wrapper for the $http service in Angular:
var filter = {
$match : {
'brand.name': brand
}
}
console.log("filter", filter);
$api.get('products', {'aggregate': filter}, function(response){
console.log(response.data);
}, function(response){
console.log("error", response.data);
})
The aggregrate parameter is correct when I log it in the function, it looks like: aggregate {$match:{'brand.name':'Microsoft'}}
Is there anybody which can tell me what I'm missing?
Solution
The aggregate function accepts an array of operations -
You need to pass this
[{$match:{'brand.name':'Microsoft'}}]
instead of this
{$match:{'brand.name':'Microsoft'}}
Alternatively in mongoose you can use pipelining like this -
Product.aggregate().match({'brand.name':'Microsoft'}).allowDiskUse(true);
Answered By - Jyotman Singh
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.