【问题标题】:Does Spring Data MongoDb support $filter array aggregations operator?Spring Data MongoDb 是否支持 $filter 数组聚合运算符?
【发布时间】:2016-09-12 22:53:31
【问题描述】:

我正在尝试使用 MongoTemplate 在 Spring Data 中实现以下工作 mongoDb 查询:

db.answers.aggregate([
        { "$match" : { "object_id" : "1" } },
        { "$project": { 'answer_list': 1, 'profile': { $filter : { input: '$answer_list', as: 'answer', cond: { $eq: [ '$$answer.question', 2 ] } } } } },
        { "$unwind" : "$profile"},
        { "$unwind" : "$answer_list"},
        { "$group" : { "_id" : { "question" : "$answer_list.question", "answer" : "$answer_list.answer", "criteria" : "$profile.answer"}, "count" : { "$sum" : 1 } } },
        { "$sort" : { "_id.question" : 1, "_id.answer" : 1 } }
]);

该集合具有以下结构:

{
"_id" : ObjectId("..."),
"object_id" : ObjectId("..."),
"answer_list" : [ 
    {
        "question" : NumberLong(0),
        "answer" : NumberLong(0)
    }, 
    {
        "question" : NumberLong(1),
        "answer" : NumberLong(2)
    }, 
    {
        "question" : NumberLong(2),
        "answer" : NumberLong(2)
    }
]}

我在这里要做的是一份关于简单调查提交数据的报告。问题是“对第一个问题回答 0 的用户如何回答第二个问题?” 我花了一整天的时间搜索 SpringData Mongo Db 文档,但一无所获。 有人可以帮忙吗?

TIA

【问题讨论】:

  • 我创建了DATAMONGO-1491 以添加对$filter 的支持。
  • 谢谢克里斯托夫。我希望在实施之前找到解决方法

标签: java spring mongodb spring-data-mongodb


【解决方案1】:

您可以通过提供自己的AggregationExpression 来解决此问题。

ProjectionOperation agg = Aggregation.project() //

      .and(new AggregationExpression() {

        @Override
        public DBObject toDbObject(AggregationOperationContext context) {

          DBObject filterExpression = new BasicDBObject();
          filterExpression.put("input", "$answer_list");
          filterExpression.put("as", "answer");
          filterExpression.put("cond", new BasicDBObject("$eq2", Arrays.<Object> asList("$$answer.question", 2)));

          return new BasicDBObject("$filter", filterExpression);
        }
      }).as("profile");

【讨论】:

  • 这正是我所需要的。唯一的问题是接口 AggregationExpression 不是公开的,如果我没有遗漏什么...
  • 我创建了jira.spring.io/browse/DATAMONGO-1492,建议接口应该是公开的。我仍在寻找一种方法来实施您的建议...
  • doh...我的错-应该公开-感谢您提出问题!由于AggregationExpression 是包私有的,您可以将包org.springframework.data.mongodb.core.aggregation 添加到您的项目中,并在该包中创建一个公共类/接口FilterExpression 实现/扩展AggregationExpression。然后从那里使用那个。
  • 我越来越近了……这是我的实现:public class FilterExpression implements AggregationExpression { // private fields and constructor omitted for brevity @Override public DBObject toDbObject( AggregationOperationContext context ) { DBObject filterExpression = new BasicDBObject(); filterExpression.put("input", input); filterExpression.put("as", as); filterExpression.put("cond", cond); return new BasicDBObject("$filter", filterExpression); } }
  • 表达式似乎是正确的(调用 toDBObject() 和 toJson() 产生:"{ "$filter" : { "input" : "$answer_list", "as" : "answer", "cond" : { "$eq2" : ["$$answer.question", 2] } } }") 但我遇到了异常:org.springframework.data.mapping.PropertyReferenceException: No property answer found for type Opinion! at org.springframework.data.mapping.PropertyPath.&lt;init&gt;(PropertyPath.java:77) ...
【解决方案2】:

还有一种使用Aggregation的替代方法

Aggregation aggregation = newAggregation(
                           project()
                           .and(filter("answer_list")
                           .as("answer")
                       .by(valueOf("answer.question").equalToValue(2)))
                           .as("profile"));
AggregationResults<OutputType> profile = mongoTemplate.aggregate(aggregation, InputType.class, OutputType.class);

我可能无法正确回答您的问题,但我只是想提供另一种聚合方法,因为使用 Aggregation 的示例数量较少。

project() 中,您可以在响应中指定所需的键,因为它是一个可变参数方法

【讨论】:

  • 我更喜欢这个答案。但是,请在答案中包含您正在使用的静态导入。对于其他人,valueOf() 运算符来自这里:import static org.springframework.data.mongodb.core.aggregation.ComparisonOperators.valueOf;
猜你喜欢
  • 2015-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-24
相关资源
最近更新 更多