I have this collection of products and i want to display a top 10 products
based on a custom sort function
[{ _id: 1, title, tags:['a'], createdAt:ISODate("2016-01-28T00:00:00Z") } ,
{ _id: 2, title, tags:['d','a','e'], createdAt:ISODate("2016-01-24T00:00:00Z") }]
What i want to do is to sort it based on a "magic score" that can be calculated. For example, based on this formula: tag_count*5 - number_of_days_since_it_was_created
.
If the first one is 1 day old, this makes the score:
[{_id:1 , score: 4}, {_id:2, score: 10}]
I have a few ideas on how i can achieve this, but i'm not sure how good they are, especially since i'm new to both mongo and meteor:
start an observer (Meteor.observe) and every time a document is modified (or a new one created), recalculate the score and update it on the collection itself. If i do this, i could just use $orderBy where i need it.
after some reading i discovered that mongo aggregate or map_reduce could help me achieve the same result, but as far as i found out, meteor doesn't support it directly
sort the collection on the client side as an array, but using this method i'm not sure how it will behave with pagination (considering that i subscribe to a limited number of documents)
Thank you for any information you can share with me!
Ascending/Descending SortSpecify in the sort parameter the field or fields to sort by and a value of 1 or -1 to specify an ascending or descending sort respectively. When comparing values of different BSON types, MongoDB uses the following comparison order, from lowest to highest: MinKey (internal type) Null.
This operation sorts the documents in the users collection, in descending order according by the age field and then in ascending order according to the value in the posts field.
MongoDB may use multiple indexes to support a sort operation if the sort uses the same indexes as the query predicate. If MongoDB cannot use an index or indexes to obtain the sort order, MongoDB must perform a blocking sort operation on the data.
Literal function sorting is just being implemented in meteor, so you should be able to do something like
Products.find({}, {sort: scoreComparator});
in an upcoming release.
You can use the transform property when creating collection. In this transform, store the magic operation as a function.
score=function(){
// return some score
};
transformer=function(product){
product.score=score;
// one could also use prototypal inheritance
};
Products=new Meteor.Collection('products',{transform:transformer});
Unfortunately, you cannot yet use the sort operator on virtual fields, because minimongo does not support it.
So the ultimate fall-back as you mentioned while nor the virtual field sorting nor the literate function sorting are supported in minimongo is client side sorting :
// Later, within some template
scoreComparator=function(prd1,prd2){
return prd1.score()-prd2.score();
}
Template.myTemplate.helpers({
products:function(){
return Products.find().fetch().sort(scoreComparator);
}
});
i'm not sure how it will behave with pagination (considering that i subscribe to a limited number of documents)
EDIT : the score will be computed among the subscribed documents, indeed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With