1

我的窗体的集合:春数据MongoDB的模拟IFNULL行为

{ "_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构造。如何管理这个问题?

回答

1

你可以创建一个实现AggregationOperation接口取一个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(); 
+1

工程就像一个魅力。谢谢 – mor