Reputation: 7853
I have an array of objects:
result = [
{ _id: 53d0dfe3c42047c81386df9d, video_id: '1' },
{ _id: 53d0dfe3c42047c81386df9e, video_id: '1' },
{ _id: 53d0dfe3c42047c81386df9f, video_id: '1' },
{ _id: 53d0dfe3c42047c81386dfa0, video_id: '2' },
{ _id: 53d0dfe3c42047c81386dfa1, video_id: '2' },
{ _id: 53d0dfe3c42047c81386dfa2, video_id: '1' },
{ _id: 53d0dfe3c42047c81386dfa3, video_id: '2' },
{ _id: 53d0dfe3c42047c81386dfa4, video_id: '1' }
]
I need to create another array, which takes video_id as the index, and contains how many times this video_id appears in the first array:
list = [
{'1' : 5},
{'2' : 4}
]
Currently, I use this code:
while (i < result.length)
{
if(list[result[i].video_id] === undefined) {
list[result[i].video_id] = 0;
}
list[result[i].video_id] = list[result[i].video_id] + 1;
i = i + 1;
}
It works, but I wonder if there is any faster and cleaner way to do so? (the real result array has over 10k elements, and I doubt >10k conditional statements are optimal...).
I am using node.js, result is from a mongoose (mongoDB) query, and I didn't see any way to get this done by mongoose itself:
var now = new Date();
//M_logs is a mongoose model
query = M_logs.where('time').gt(new Date(now.getFullYear(), 0, 1).getTime() / 1000).lt(now.getTime() / 1000).select('video_id');
(PS: I wonder if this isn't more a Code Review question, please tell me if I am off-topic so I can migrate the question).
EDIT:
To answer to Juan Carlos Farah:
S_logs = new mongoose.Schema({
user_ip : String,
user_id : String,
user_agent : String,
canal_id : String,
theme_id : String,
video_id : String,
osef : String,
time : Number,
action: String,
is_newuser : String,
operator : String,
template : String,
catalogue : String,
referer : String,
from : String,
osef1 : String
});
M_logs = mongoose.model('logs', S_logs);
Upvotes: 1
Views: 116
Reputation: 3879
You can do this using the aggregation framework. The idea is to do something as follows:
time
is between new Date(now.getFullYear(), 0, 1).getTime() / 1000
and now.getTime() / 1000
.video_id
and keep track of their count._id
, which would be equivalent to the original video_id
. The following is in mongo
shell syntax:
var now = new Date();
db.M_logs.aggregate([
{
"$match" : {
"time" : {
"$gt" : new Date(now.getFullYear(), 0, 1).getTime() / 1000,
"$lt" : now.getTime() / 1000
}
}
},
{
"$group" : {
"_id" : "$video_id",
"count" : { "$sum" : 1 }
}
},
{
"$sort" : { "_id" : 1 }
}
]);
If this works for you, you can easily implement it in Mongoose or Node.js driver syntax. Note that the aggregation framework returns a cursor, which you can iterate through to populate your array.
EDIT:
Using the Node.js driver, you can access the results from the aggregation query in the callback function. Something as follows:
...
, function(err, result) {
console.dir(result);
db.close();
}
Note that the Mongoose syntax for aggregation queries is slightly different.
Example:
Model.aggregate([ <QUERY> ]).exec( <CALLBACK> );
For more information, consult the documentation here.
Upvotes: 2
Reputation: 12240
I would suggest that you use aggregation framework to count number of documents. It will be significantly faster than iterating all your documents and counting them.
Using mongoose you can do it like this:
var now = new Date();
var startTime = new Date(now.getFullYear(), 0, 1).getTime() / 1000):
var endTime = now.getTime() / 1000;
M_logs.aggregate([
// filter the documents you're looking for
{"$match" : { "time" : {"$gt": startTime, "$lt": endTime}}},
// group by to get the count for each video_id
{"$group" : {"_id" : "$video_id", "count" : {"$sum" : 1}}},
// make the output more explanatory; this part is optional
{"$project" : { "video_id" : "$_id", "count" : "$count", _id : 0}}
]).exec(function(err, docs){
if (err) console.err(err);
console.log(docs);
});
The output of the docs
will be:
[ { count: 4, video_id: '2' }, { count: 5, video_id: '1' } ]
Upvotes: 1
Reputation: 2969
use
var list = {};
result.forEach(function (el) {
list[el.video_id] = (list[el.video_id] || 0) + 1;
});
the resuling list will look something like this:
var list = {
'1': 5,
'2': 4
};
Upvotes: 0