问题
My data mongoDB
:
>db.CUSTOMER.find()
{"Name": "A", "CreatedDate": "Wed Jan 29 2014"}
{"Name": "B", "CreatedDate": "Fri Jan 31 2014"}
{"Name": "C", "CreatedDate": "Sat Feb 01 2014"}
{"Name": "D", "CreatedDate": "Sat Feb 01 2014"}
In meteor:
Customer = new Meteor.Collection("CUSTOMER");
I'm trying to group them by date (Mon, Tues, Wed, ...) in meteor collection along with the total of the data. It should be something like this:
{"Date": "Wed Jan 29 2014", "Total" 1}
{"Date": "Fri Jan 31 2014", "Total" 1}
{"Date": "Sat Feb 01 2014", "Total" 2}
In mongoDB, I'd just go with http://docs.mongodb.org/manual/reference/method/db.collection.group/, but apparently, it is impossible in meteor, for it doesn't support findAndModify, upsert, aggregate functions, and map/reduce.
Is there any examples of workaround that I can do to make it works?
Thank you
回答1:
You'll need to group them manually. There are a number of ways to do that, but here's an (admittedly difficult to read) example:
var customers = Customer.find().fetch();
var groupedDates = _.groupBy(_.pluck(customers, 'CreatedDate'));
_.each(_.values(groupedDates), function(dates) {
console.log({Date: dates[0], Total: dates.length});
});
回答2:
You can user those functions with meteor, you are talking about, or found a link to what describes the client side processing, but from the server side it is different.
You should be using aggregate rather than the mapReduce or group functions for most cases. The whole pipeline is implemented in C++ rather than passing onto the JavaScript engine. In all cases the equivalent functions in aggregation pipeline will be faster.
> db.dates.aggregate([
{$group: { _id: {$dayOfWeek: "$CreatedDate"}, Total: {$sum: 1} }},
{$project: { _id: 0, day: "$_id", Total: 1 } },
{$sort: { day: 1 }}
])
{
"result" : [
{
"Total" : 1,
"day" : 4
},
{
"Total" : 1,
"day" : 6
},
{
"Total" : 2,
"day" : 7
}
],
"ok" : 1
}
About Meteor Support
Server side, meteor uses the node-mongodb-native driver for all processing. It is maintained by MongoDB and maintains all features.
Client side is a library known as "mini-mongo". This is not actually a driver but a little layer that is actually using sockets connections to pass details through to the server. It makes your client side javascript "look" the same as server side code, but you are not actually talking to mongo directly.
There is nothing wrong with using server side functions that are "published" to the client
to invoke your custom code on the server
side. As said, it's just the standard driver you can use in other nodejs applications.
回答3:
I want to add comment, but my reputation is too low. Just use _.countBy may be more readable.
_.countBy(customers,function(customer){return customer.CreatedDate})
This should return a dict ([CreatedDate]:count)
Hope this helps
回答4:
Complementing the responses above:
- you cannot use all the mongo functions on the client, because meteor relies on
mini-mongo
that only implements a subset of the mongo functions, and is not particularly efficient. So on the client your best options is to go with some underscore functions as described by @david weldon. From what I've heard, mini-mongo is also just a bunch of underscore functions, and only index on ids. - you can still use all the mongo functions on the server, but this will feel a bit hacky since Meteor is trying to hide them behind its wrapping. Still, this is probably much more efficient. Here is how it'd look like:
.
mongoCustomer = Customer._collection.rawCollection() // you're now on the mongo realm
mongoCustomer.aggregate([
{
$group: {
_id: "$CreatedDate",
Total: { $sum: 1 }
}
}
], function(err, agg) {
if (err) {
...
return;
}
// agg an array of { CreatedDate, Total }, do what you want with it
});
So that's nice, but you also lose the synchronous looking syntax Meteor gives you with Customer.find(...).fetch()
. You can now wrap the mongo aggregation in a Promise and use await/async if you want to get that syntax back.
来源:https://stackoverflow.com/questions/21692965/group-by-queries-on-meteor-collection