Random documents from MongoDB using spring-data

廉价感情. 提交于 2019-12-01 06:29:11
Blakes Seven

Update:

Starting with v2.0 of Spring Data you can do this:

SampleOperation matchStage = Aggregation.sample(5);
Aggregation aggregation = Aggregation.newAggregation(sampleStage);
AggregationResults<OutType> output = mongoTemplate.aggregate(aggregation, "collectionName", OutType.class);

Original answer:

Abstraction layers like spring-mongo are always going to lag way behind server released features. So you are best off contructing the BSON document structure for the pipeline stage yourself.

Implement in a custom class:

public class CustomAggregationOperation implements AggregationOperation {
    private DBObject operation;

    public CustomAggregationOperation (DBObject operation) {
        this.operation = operation;
    }

    @Override
    public DBObject toDBObject(AggregationOperationContext context) {
        return context.getMappedObject(operation);
    }
}

And then use in your code:

Aggregation aggregation = newAggregation(
    new CutomAggregationOperation(
        new BasicDBObject(
            "$sample",
            new BasicDBObject( "size", 15 )
        )
    )
);

Since this implements AggregationOperation this works well with the exising pipeline operation helper methods. i.e:

Aggregation aggregation = newAggregation(
    // custom pipeline stage
    new CutomAggregationOperation(
        new BasicDBObject(
            "$sample",
            new BasicDBObject( "size", 15 )
        )
    ),
    // Standard match pipeline stage
    match(
        Criteria.where("myDate")
            .gte(new Date(new Long("949384052490")))
            .lte(new Date(new Long("1448257684431")))
    )
);

So again, everything is just a BSON Object at the end of the day. It's just a matter of having an interface wrapper so that the class methods in spring-mongo interpret the result and get your defined BSON Object correctly.

Blakes Seven answered it correctly, however, I want to offer a nicer implementation of AggregationOperation, which follows standard Spring implementation

import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.util.Assert;

public class SampleOperation implements AggregationOperation  {

    private int size;

    public SampleOperation(int size) {
        Assert.isTrue(size > 0, " Size must be positive!");
        this.size = size;
    }

    public AggregationOperation setSize(int size) {
        Assert.isTrue(size > 0, " Size must be positive!");
        this.size = size;
        return this;
    }

    @Override
    public DBObject toDBObject(AggregationOperationContext context) {
        return new BasicDBObject("$sample", context.getMappedObject(Criteria.where("size").is(size).getCriteriaObject()));
    }

}

After that, you can create SampleOperation object with constructor, or later change the size of it by setSize() method, and apply it to aggregate() function as normal.

Update: In SpringBoot 2.0.0+ and Spring Framework 5.0: Spring Mongo drop DBObject and replace by org.bson.Document therefore the last past should be updated as:

    @Override
public Document toDocument(AggregationOperationContext aggregationOperationContext) {
    return new Document("$sample", aggregationOperationContext.getMappedObject(Criteria.where("size").is(size).getCriteriaObject()));

}

And remove the @Override toDBObject

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!