【问题标题】:Spring + MongoDB tag @Query with $group not workingSpring + MongoDB 标记 @Query 与 $group 不工作
【发布时间】:2016-12-15 20:56:54
【问题描述】:

注意:向下查看编辑后的消息。

我正在尝试模仿这个查询:

db.sentiments.aggregate([
{"$group" : {_id:{theme_id:"$theme",sentiment_id:"$sentiment"}, count:{$sum:1}}},
{"$sort":{"_id.theme_id":1}} ])

这是我为模仿它而生成的代码:

    @RepositoryRestResource(collectionResourceRel = "sentiments", path = "sentiments")
public interface SentimentsRepository extends MongoRepository<Sentiments, String> {
    Long countByTheme(@Param("theme") String theme);

@Query(value ="[\n" +
        "    {\"$group\" : {_id:{theme_id:\"$theme\",sentiment_id:\"$sentiment\"}, count:{$sum:1}}},\n" +
        "\t{\"$sort\":{\"_id.theme_id\":1}}\n" +
        "]",count = true)
List<Object> comptarSentiments();

} 那么这段代码返回给我这个错误:

"exception": "org.springframework.data.mongodb.UncategorizedMongoDbException",


"message": "Can't canonicalize query: BadValue unknown operator: $group; nested exception is com.mongodb.MongoException: Can't canonicalize query: BadValue unknown operator: $group",

其实我是Spring的初学者,所以我很迷茫,有人知道我该怎么办吗?

感谢和抱歉我的英语不好,不是我的母语。

[编辑]---------------------------------------- 正如 Shawn Clark 所写的评论那样,这样做是不可能的,为了实现这一点,您需要创建一个 customRepository。

What's the difference between Spring Data's MongoTemplate and MongoRepository?

我一直在尝试这样做,但似乎有些不正确,这是我的新代码:

@RepositoryRestResource(collectionResourceRel = "sentiments", path = "sentiments")
public interface SentimentsRepository extends CrudRepository<Sentiments, String>, CustomSentimentsRepository {

//Other methods...

}

public interface CustomSentimentsRepository {

    List<CountResult> yourCustomMethod();

    class CountResult{
        String theme;
        String sentiment;
        int total;
    }
}

public class SentimentsRepositoryImpl implements CustomSentimentsRepository {
    private final MongoOperations operations;


    @Autowired
    public SentimentsRepositoryImpl(MongoOperations operations) {

        Assert.notNull(operations, "MongoOperations must not be null!");
        this.operations = operations;
    }

    @Override
    public List<CountResult> yourCustomMethod(){
        Aggregation agg = Aggregation.newAggregation(
                Aggregation.group("theme","sentiment").count().as("total"),
                Aggregation.project("theme","sentiment").and("total").previousOperation(),
                Aggregation.sort(Sort.Direction.DESC, "theme")
        );

        //Convert the aggregation result into a List
        AggregationResults<CountResult> groupResults
                = operations.aggregate(agg,"sentiments",  CountResult.class);
        //List<CountResult> result = groupResults.getMappedResults();

        return groupResults.getMappedResults();
    }
}

我什至无法调试这段代码,而且总是得到 404。

【问题讨论】:

    标签: spring mongodb


    【解决方案1】:

    根据我发现的信息,您无法在 MongoRepository 方法上执行 @Query 的复杂操作。在这种情况下,您需要创建一个类并使用 mongoTemplate 实现您的 comptarSentiments() 方法,以使用您的聚合函数查询数据存储。然后创建一个公开 REST 端点的控制器类并让它调用存储库。

    一旦您开始在 Mongo 中执行复杂的查询,您就会失去 @RepositoryRestResource 的便利性,并且必须自己重新将 REST 端点连接到存储库。

    Spring Data REST : custom query for MongoDB repository

    Implementing custom methods of Spring Data repository and exposing them through REST

    【讨论】:

    • 您好,看来您是对的,但我仍然遇到问题,请您看一下编辑消息吗?非常感谢。
    • 您如何尝试调用端点?什么给了你 404?您有可以共享的控制器类代码吗?
    • 您又说对了,我的控制器中的拼写错误导致了问题,我感到有些惭愧,非常感谢您的关注。 ;)
    【解决方案2】:

    我终于设法解决了这个问题,似乎它与控制器和innerClass CountResult中的属性“total”的类型有关,它需要是一个String(这很重要,否则Aggregation.project将失败)。最终代码如下:

    public interface CustomSentimentsRepository {
    
        List<CountResult> myCountGroupByThemeAndSentiment();
    
        class CountResult{
            public String theme;
            public String sentiment;
            public String total;
        }
    }
    
    public class SentimentsRepositoryImpl implements CustomSentimentsRepository {
        private final MongoTemplate mongoTemplate;
    
    
        @Autowired
        public SentimentsRepositoryImpl(MongoTemplate mongoTemplate) {
    
            this.mongoTemplate = mongoTemplate;
        }
    
        @Override
        public List<CountResult> myCountGroupByThemeAndSentiment(){
            Aggregation agg = Aggregation.newAggregation(
                    Aggregation.group("theme","sentiment").count().as("total"),
                    Aggregation.project("theme","sentiment").andInclude("total"),
    
    
            Aggregation.sort(Sort.Direction.ASC,"theme","sentiment")
        );
    
    
        AggregationResults<CountResult> groupResults
                = mongoTemplate.aggregate(agg,"sentiments",  CountResult.class);
    
    
            return groupResults.getMappedResults();
        }
    }
    
    @RepositoryRestResource(collectionResourceRel = "sentiments", path = "sentiments")
    public interface SentimentsRepository extends CrudRepository<Sentiments, String>, CustomSentimentsRepository {
        //Other methods
    
    }
    
    @RestController
    @RequestMapping(value = "sentiments/search")
    public class ChartsController {
        @Autowired
        private SentimentsRepository sentimentsRepository;
    
        @RequestMapping(value = "myCountGroupByThemeAndSentiment", method = RequestMethod.GET)
        public ResponseEntity<?> yourCustomMethod() {
            List<?> count=sentimentsRepository.myCountGroupByThemeAndSentiment();
            return new ResponseEntity(count, HttpStatus.OK);
        }
    
    }
    

    【讨论】:

      【解决方案3】:

      您可以使用 spring data mongodb 2.2.X 版本中可用的@Aggrgation:

      @Aggregation(pipeline = {"{ '$group': { '_id' : '$lastname', names : { $addToSet : '$?0' } } }", "{ '$sort' : { 'lastname' : -1 } }"}) List&lt;PersonAggregate&gt; groupByLastnameAnd(String property);

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-23
        • 2017-08-06
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多