Xerif917
Xerif917

Reputation: 132

Select one of each type from collection

I have a Meteor collection that has a field called type. I'm wondering if there's a way to select one document of each type. For example, if I had the following documents in my collection (sorted by descending createdAt)

Document #1: {type = "apple", createdAt: ...}
Document #2: {type = "apple", createdAt: ...}
Document #3: {type = "grape", createdAt: ...}
Document #4: {type = "orange", createdAt: ...}
Document #5: {type = "orange", createdAt: ...}
Document #6: {type = "grape", createdAt: ...}
Document #7: {type = "apple", createdAt: ...}
...

Then how could I select 3 documents each with a unique type? In this example, I would need Document #1, #3, and #4.

Upvotes: 1

Views: 1983

Answers (2)

FullStack
FullStack

Reputation: 6030

You could first find all the distinct types with

var distinctTypes = db.mycollection.distinct("type");

and then you can loop through to push all the documents from findOne like so

var docs = [];
distinctTypes.forEach(function (thisType) {
  docs.push(db.mycollection.findOne({type: thisType});
});

From here you can alter the above code to specify which one you want if there are multiples of each type.

UPDATE: Since Meteor still doesn't support distinct, you can use the underscore uniq like so

var distinctTypes = _.uniq(Collection.find({}, {
    sort: {type: 1}, fields: {type: true}
}).fetch().map(function(x) {
    return x.type;
}), true);

Upvotes: 3

Marin
Marin

Reputation: 307

You can do this in two steps: first, you get the counts using $group, identified by type, then $match all that have count = 1.

db.fruit_collection.aggregate([
    { $match: {
        createdAt: { $gt: ISODate("2015-08-01T12:00:00Z") }
    }}, 
    { $group: {
        _id: "$type",
        count: { $sum: 1 }
    }}, 
    { $match: { 
        count: 1
    }}
]);

The first $match is there as an example, so you can ignore. The second and the third part should give you the desired result.

Upvotes: 0

Related Questions