【问题标题】:How to implement $SetIsSubset in mongoTemplate aggregation of Java Spring?如何在Java Spring的mongoTemplate聚合中实现$SetIsSubset?
【发布时间】:2016-12-13 09:26:01
【问题描述】:

我正在尝试在 mongoTemplate 聚合类中使用 $setIsSubset。但找不到任何解决方案。

我的 Mongo 查询是:

db.events.aggregate([
    { $match: { $and: [ 
        { "event_state" : {$in : ["live","scheduled"]} }, 
        { "schedule.end_time" : {$gt : ISODate("2016-12-12T06:30:00.000Z")} }
        ] 
      } 
    },
    {$project: 
        { 
            "name" :1, 
            "category" :1,
            "schedule":1, 
            "celebrity" :1,
            "online_moderator" :1,
            "offline_moderator" :1,
            "region" :1,
            "status" :1,
            "event_state" :1,
            "recorder_id" :1,
            "webcast_url":1,
            "replay_url":1,
            "registered_users":1,
            registeredUsers: { $size:"$registered_users" },
            is_registered:
            { $setIsSubset: [[ObjectId("584e6253e17ed10f0a8cba1d"),ObjectId("583e9719e17e8c1bf80da2fe")], "$registered_users.user_id"]}
        }
    },
    { $sort : {
            "schedule.start_time": 1
        }
    }
]);

我已经转换了大部分代码,如下所示。但是遇到了 $setIsSubset 条件。

matchCondition = Aggregation.match(Criteria.where("event_state")
                    .in(listEventStates).and("schedule.end_time").gt(d));

AggregationOperation projectValues = Aggregation.project()
                .and("registered_users").size().as("registered_users_count")
                .and("name").as("name").and("category").as("category")
                .and("schedule").as("schedule").and("online_moderator")
                .as("online_moderator").and("offline_moderator")
                .as("offline_moderator").and("region").as("region")
                .and("status").as("status").and("event_state")
                .as("event_state").and("recorder_id").as("recorder_id")
                .and("webcast_url").as("webcast_url").and("replay_url")
                .as("replay_url");

sortCondition = Aggregation.sort(Sort.Direction.ASC,
                    "schedule.start_time");

Aggregation aggrigation = Aggregation.newAggregation(matchCondition,
                sortCondition, projectValues);

编辑:

根据@user_531 的请求。我正在用对我有用的可能解决方案来更新我的问题。我不知道它是否会起作用,因为我使用该解决方案已经 2 年了。在那之后,我又改了几次代码,我不再维护这个项目了。但值得一试。

AggregationOperation projectValues = Aggregation.project().and("registered_users").size()
            .as("registered_users_count").and("event_image").as("event_image")
            .and("name").as("name").and("category").as("category").and("schedule").as("schedule")
            .and("region").as("region").and("status").as("status").and("event_state").as("event_state")
            .and("recorder_id").as("recorder_id").and("webcast_url").as("webcast_url").and("replay_url")
            .as("replay_url").and("registered_users").as("registered_users").and("room_details").as("room_details")
            .and("live_stream_url").as("live_stream_url")
            .and(new AggregationExpression() {        
                public DBObject toDbObject(AggregationOperationContext context) {
                    return new BasicDBObject("$setIsSubset", Arrays.<Object> asList(
                    Arrays.<Object> asList(new ObjectId("58528314e17edbb252692815")),
                        "$registered_users.user_id")); 
                } 
            }).as("is_registered");

    Aggregation aggrigation = Aggregation.newAggregation(matchCondition, sortCondition, projectValues);

    AggregationResults<Events> results = mongoTemplate.aggregate(aggrigation, "events", Events.class);

【问题讨论】:

    标签: java spring spring-mvc mongotemplate


    【解决方案1】:

    使用AggressionExpression。在项目中包括以下投影。使用 1.8.5 spring mongo 数据版本。

    and(new AggregationExpression() {
        @Override
        public DBObject toDbObject(AggregationOperationContext context) {
            return new BasicDBObject("$setIsSubset",
                    Arrays.<Object> asList(
                            Arrays.<Object> asList("584e6253e17ed10f0a8cba1d",
                                    "583e9719e17e8c1bf80da2fe"),
                            "$registered_users.user_id"));
        }
    }).as("is_registered"));
    

    您可以将表达式包装为 Java 8 的 lambda

    and(context -> new BasicDBObject("$setIsSubset",
            Arrays.<Object> asList(
                    Arrays.<Object> asList("584e6253e17ed10f0a8cba1d",
                             "583e9719e17e8c1bf80da2fe"),
                    "$registered_users.user_id")))
    .as("is_registered"));
    

    【讨论】:

    • 感谢@Sagar Reddy。您的解决方案解决了(不是 lamda 表达式)。但是需要做一个小的修正。也就是说,setIsSubset 运算符“$setIsSubset”中应该只有一个 $,而不是“$$setIsSubset”。还要感谢有关依赖项(1.8.5)的说明。我的是1.8.0。所以我相应地改变了它。
    • AggregationExpression 中没有方法 public DBObject toDbObject(AggregationOperationContext context) 可以覆盖。也许是因为依赖版本。
    【解决方案2】:

    您可以将 Mongodb api 用于项目 (com.mongodb.client.model.Aggregates.project) 也可用于匹配 (com.mongodb.client.model.Aggregates.match(Bson 过滤器)) 您可以使用我刚刚完成的代码,例如使用 $setIsSubset

    用这个查询

    db.getCollection('collection').aggregate(
     {    $match : {"_id" : "dff26f9c-350b-4bd5-bc62-62c19f21100c"}   },
    { "$project": {
           "sensorId": 1,   "sensorModel": 1,
       "attachments": {
         "$filter": {
       "input": "$attachments",
       "as": "attachment",
       "cond": {
         "$setIsSubset": [
           ["$$attachment.type"],
           ["StructAttachment", "BlobAttachment"]
         ]
       }    }   } }})
    

    而java代码是这样的:

    List <Bson> aggregationInput = new ArrayList <Bson> ();
    aggregationInput.add(match(eq("_id",id)));
    HashMap<String, Integer> fieldsMap=new HashMap<String, Integer>();
    fieldsMap.put("sensorId", 1);
    fieldsMap.put("sensorModel", 1);
    
    ArrayList< ArrayList<String>> isSubset = new ArrayList< ArrayList<String>>();
    ArrayList<String> isSubsetParameter1 = new ArrayList<String>();
    isSubsetParameter1.add("$$attachment.mimeType");
    
    ArrayList<String> isSubsetParameter2 = new ArrayList<String>();
    isSubset.add(isSubsetParameter1 );
    isSubset.add(isSubsetParameter2 );
    
    Document docFields = new Document();
    if (mimeTypes == null || mimeTypes.isEmpty()) {
    

    //mimeTypes 是一个集合 isSubsetParameter2.addAll(mimeTypes);

    Document filter = new Document();
    filter.put("input", "$attachments");
    filter.put("as", "attachment");
    filter.put("cond", new  Document("$setIsSubset", isSubset));
    
    docFields.put("attachments", new Document("$filter",filter));
    docFields.putAll(fieldsMap);
    aggregationInput.add(project(docFields));
    
    AggregateIterable<Document> resultIteratr = mongo.getDatabase("db").getCollection("collection")
    .aggregate(aggregationInput);
    

    我希望这对你有用!

    【讨论】:

    • 我正在研究您的解决方案。但我正在努力将对象添加到 isSubset 中。因为一个参数是一个字符串,另一个是一个对象。例如:isSubsetParameter1.add("$$registered_users.user_id");第二个值为user_id,是ObjectId类型。
    • 不幸的是,您 (@Guel135) 建议的解决方案对我不起作用。因为我必须在同一个数组列表数据“isSubset”中使用字符串和对象。所以我使用了一些其他的方法来实现同样的效果,通过循环子文档。
    • @Kiran 请问您能提供上述解决方案吗?
    • @user_531,我使用这个逻辑已经有 2 年了。我试图挖掘代码,看起来我在那里做了不同的方法。但会尝试发布代码供您参考。不知道这是否对你有用!我将用答案编辑我的问题。请看一看。谢谢。
    • @kiran 非常感谢您抽出时间来做这件事。它对我有用:)
    猜你喜欢
    • 2020-09-28
    • 2019-10-14
    • 1970-01-01
    • 2016-04-14
    • 1970-01-01
    • 2019-04-12
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    相关资源
    最近更新 更多