I'm working on a simple dev-meet-designer platform, and I am trying to create a better popularity ranking algorithm.
My existing code is:
project_collection.aggregate([
{ "$project": {
"score": {
"$divide": [
"$views",
{ "$divide": [
{ "$subtract": [
new Date(),
"$created_at"
]},
10*60*30
]}
]},
"created_at": 1,
"views": 1
}}
], function(error, results) {
// do stuff
});
I want to switch the code to count the likers array from the document, and use that value in place of $views. Any help is greatly appreciated!
Here's an example document structure:
{
"_id" : ObjectId("53d95d33a3ca780d096e5e7e"),
"name" : "Foo",
"tagline" : "This is a test project.",
"description" : "Foo bar.",
"tags" : [
"front end"
],
"owner" : "Noah",
"views" : 2,
"activity" : [
{
"options" : {
"type" : "started",
"owner" : "Noah"
}
},
{
"options" : {
"type" : "application",
"applicant" : "John"
}
}
],
"closed" : false,
"finished" : false,
"applicants" : [ "John" ],
"partners" : [],
"chat" : [],
"discussion" : [],
"url" : "",
"fireQuene" : [],
"likers" : [ "John", "Noah" ],
"created_at" : ISODate("2014-07-30T21:01:39.421Z")
}
To get the "array length" as your question asks MongoDB 2.6 introduced the $size operator which returns the length of an array. Used in place of "$views" in your algorithm this would be:
project_collection.aggregate([
{ "$project": {
"score": {
"$divide": [
{ "$size": "$likers" },
{ "$divide": [
{ "$subtract": [
new Date(),
"$created_at"
]},
10*60*30
]}
]},
"created_at": 1,
"views": 1
}}
], function(error, results) {
// do stuff
});
If you have an earlier version without this feature then you need to use $unwind on the array and $sum to get the count. This you can move into the $group stage:
project_collection.aggregate([
{ "$unwind": "$likers" },
{ "$group": {
"_id": "$_id",
"created_at": { "$first": "$created_at" },
"likers": { "$push": "$likers" },
"count": { "$sum": 1 }
}},
{ "$project": {
"score": {
"$divide": [
"$count",
{ "$divide": [
{ "$subtract": [
new Date(),
"$created_at"
]},
10*60*30
]}
]},
"created_at": 1,
"views": 1
}}
], function(error, results) {
// do stuff
});
So $size helps you with what you are doing , but otherwise it is generally a good idea to try and keep a "count" of your likers within your document and update that accordingly.