java - Spring data mongodb 模拟 ifNull 行为

标签 java spring mongodb aggregation-framework spring-data-mongodb

我有一组表格:

{ "_id" : { "$oid" : "57050f22d5f79d2e6866c6f8" }, "form_name" : "Form 1", "ver" : 0, "createdAt" : { "$date" : 1459950030037 } }
{ "_id" : { "$oid" : "57050fa6d5f79d2e6866c6f9" }, "form_name" : "Form 1", "ver" : 1, "vid" : { "$oid" : "57050f22d5f79d2e6866c6f8" }, "createdAt" : { "$date" : 1459950030037 } }
{ "_id" : { "$oid" : "57050ff2d5f79d2e6866c6fa" }, "form_name" : "Form 1", "ver" : 2, "vid" : { "$oid" : "57050f22d5f79d2e6866c6f8" }, "createdAt" : { "$date" : 1459950030037 } }
{ "_id" : { "$oid" : "570511ced5f79d2e6866c6fb" }, "form_name" : "Form 2", "ver" : 0, "createdAt" : { "$date" : 1459950030037 } }

我收到的版本化表单如下:

db.forms.aggregate([
    {"$match":{"deletedAt":{"$exists":false}}},
    {"$sort":{"createdAt":1}},
    {"$group":{
            "_id": {"$ifNull":["$vid", "$_id"]},
            "vid":{"$push":"$$ROOT"}
        }
    }
])

我得到了这样的 JSON 答案:

[
    {
        "_id" : ObjectId("57050f22d5f79d2e6866c6f8"),
        "vid" : [
            {
                "_id" : ObjectId("57050f22d5f79d2e6866c6f8"),
                "form_name" : "Form 1",
                "ver" : 0,
                "createdAt" : ISODate("2016-04-06T13:29:06.079Z")
            },
            {
                "_id" : ObjectId("57050fa6d5f79d2e6866c6f9"),
                "form_name" : "Form 1",
                "ver" : 1,
                "createdAt" : ISODate("2016-04-06T13:31:18.742Z"),
                "vid" : ObjectId("57050f22d5f79d2e6866c6f8")
            },
            {
                "_id" : ObjectId("57050ff2d5f79d2e6866c6fa"),
                "form_name" : "Form 1",
                "ver" : 2,
                "createdAt" : ISODate("2016-04-06T13:32:34.986Z"),
                "vid" : ObjectId("57050f22d5f79d2e6866c6f8")
            }
        ]
    },
    {
        "_id" : ObjectId("570511ced5f79d2e6866c6fb"),
        "vid" : [
            {
                "_id" : ObjectId("570511ced5f79d2e6866c6fb"),
                "form_name" : "Form 2",
                "ver" : 0,
                "createdAt" : ISODate("2016-04-06T13:40:30.037Z")
            }
        ]
    }
]

在我的 Java 后端中,我的做法如下:

List<DBObject> tmpAggr = new ArrayList<>();
tmpAggr.add(new BasicDBObject("$match", new BasicDBObject("deletedAt", new BasicDBObject("$exists", false))));
tmpAggr.add(new BasicDBObject("$sort",  new BasicDBObject("createdAt", 1)));
tmpAggr.add(new BasicDBObject("$group", BasicDBObjectBuilder.start("_id", new BasicDBObject("$ifNull", new String[]{"$vid", "$_id"}))
                                                        .append("vid", new BasicDBObject("$push", "$$ROOT")).get()));
tmpAggr.add(new BasicDBObject("$sort",  new BasicDBObject("_id", 1)));
        list_with_versions = Collections.unmodifiableList(tmpAggr);  
org.getDB().getCollection("forms").aggregate(list_with_versions).results()

如何使用 Spring Data MongoDB 框架重现此行为? 问题是没有 ifNull 构造。如何解决这个问题?

最佳答案

您可以创建一个解决方法来实现 AggregationOperation 接口(interface)采用 DBObject 表示聚合管道中的单个操作,并使用 $ifNull 运算符:

public class GroupAggregationOperation implements AggregationOperation {
    private DBObject operation;

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

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

然后将 $group 操作实现为聚合管道中的 DBObject,该管道与您拥有的管道相同:

DBObject operation = (DBObject) new BasicDBObject(
    "$group", BasicDBObjectBuilder.start(
        "_id", new BasicDBObject(
            "$ifNull", new String[]{"$vid", "$_id"}
        )
    )
    .append("vid", new BasicDBObject("$push", "$$ROOT"))
    .get()              
);

然后您可以将其用作:

import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

GroupAggregationOperation groupOp = new GroupAggregationOperation(operation);
Aggregation agg = newAggregation(
    match(Criteria.where("deletedAt").exists(false)),
    sort(ASC, "deletedAt"),
    groupOp 
);
AggregationResults<Forms> results = mongoTemplate.aggregate(agg, Forms.class); 
List<Forms> forms = results.getMappedResults();

关于java - Spring data mongodb 模拟 ifNull 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36454383/

相关文章:

Java thymeleaf : Could not parse expression

java - 如果代理关闭,则无法创建 Bean

java - 如何在 Google 应用引擎中获取当前登录用户

node.js - Mongoose 排除数组中的字段

node.js - Mongoose 发现卡在上面返回的 101 项

java - 客户端发送的请求在语法上不正确,multipart/form-data 和 content-length 大于 9375 字节

java - Java ThreadPoolExecutor 线程死亡时执行资源释放 Action

node.js - mongoDB:聚合 - 是否有等效于 native node.js 驱动程序的 $lookup 连接?

java - setOnclicklistener 方法不起作用

spring - 无法在Grails Hibernate中将数据库状态与 session 错误同步