Radu Bogdan
Radu Bogdan

Reputation: 504

custom sort for a mongodb collection in meteor

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:

  1. 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.

  2. 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

  3. 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!

Upvotes: 6

Views: 2261

Answers (1)

Jules Sam. Randolph
Jules Sam. Randolph

Reputation: 4270

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.

Upvotes: 7

Related Questions