如何在Spring-Data-MongoDB [春季data-mongodb]中使用$累加器[mongodb]

发布于 2025-02-12 19:57:09 字数 11129 浏览 2 评论 0原文

我是Spring-Data-MongoDB的新手,我正在开发一种在Spring-Data-MongoDB中执行MongoDB $累加器操作员的方法,但是我不知道为什么我在$ aggipulator上的结果字段返回null。

现在,我正在MongoDB中填充该集合:

db.game.insertMany([
{ "_id" : 1, "name" : "John", "score" : 10},
{ "_id" : 2, "name" : "Elizabeth", "score" : 10},
{ "_id" : 3, "name" : "James ", "score" : 9},
{ "_id" : 4, "name" : "John", "score" : 5},
{ "_id" : 5, "name" : "Elizabeth", "score" : 10},
{ "_id" : 6, "name" : "John", "score" : 10},
{ "_id" : 7, "name" : "Elizabeth", "score" : 10},
{ "_id" : 8, "name" : "James ", "score" : 8 },
{ "_id" : 9, "name" : "James ", "score" : 8}])

这是MongoDB服务器中的累加器聚合:

db.game.aggregate ([
{
  $group :
  {
    _id : "$name",
    avgScore:
    {
      $accumulator:
      {
        init: function() {                        
          return { count: 0, sum: 0 }
        },
        accumulate: function(state, score) {                
          return {
            count: state.count + 1,
            sum: state.sum + score
          }
        },
        accumulateArgs: ["$score"],      
       
        merge: function(state1, state2) {        
          return {                              
            count: state1.count + state2.count,
            sum: state1.sum + state2.sum
          }
        },
        finalize: function(state) {               
          return (state.sum / state.count)       
        },
        lang: "js"
      }
    }
  }
}
])

这是我试图通过Spring-Data-MongoDB执行的MongoDB的结果:

{ "_id" : "Elizabeth", "avgScore" : 10 }
{ "_id" : "John", "avgScore" : 8.333333333333334 }
{ "_id" : "James ", "avgScore" : 8.333333333333334 }

这是我的RestController的结果:

[
    {
        "name": "Elizabeth",
        "avgScore": null
    },
    {
        "name": "James ",
        "avgScore": null
    },
    {
        "name": "John",
        "avgScore": null
    }
]

这是模型类

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection="game")
public class Game {
    @Id
    private Integer _id;
    private String name;
    private Integer score;
    public Game() {
        super();
        // TODO Auto-generated constructor stub
    }
    public int get_id() {
        return _id;
    }
    public void set_id(Integer _id) {
        this._id = _id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getScore() {
        return score;
    }
    public void setScore(Integer score) {
        this.score = score;
    }

}

这是在累加器方法上执行$累加器运算符的服务,但它返回null:

import java.util.LinkedList;
import java.util.List;
import com.project.ecommercemongo.aggregation.ResultAccumulator;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationExpression;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
import org.springframework.data.mongodb.core.aggregation.ScriptOperators;
import org.springframework.data.mongodb.core.aggregation.ScriptOperators.Accumulator;
import org.springframework.data.mongodb.core.aggregation.ScriptOperators.Accumulator.AccumulatorAccumulateArgsBuilder;
import org.springframework.data.mongodb.core.aggregation.ScriptOperators.Accumulator.AccumulatorFinalizeBuilder;
import org.springframework.data.mongodb.core.aggregation.ScriptOperators.Accumulator.AccumulatorInitArgsBuilder;
import org.springframework.data.mongodb.core.aggregation.ScriptOperators.Accumulator.AccumulatorInitBuilder;
import org.springframework.data.mongodb.core.aggregation.ScriptOperators.Accumulator.AccumulatorMergeBuilder;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.group;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation;
import org.springframework.stereotype.Service;
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
import com.project.ecommercemongo.model.Game;
import com.project.ecommercemongo.repository.GameRepository;

@Service
public class GameService {
    @Autowired
    GameRepository game;
    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    private MongoOperations mongoOperations;

    public List<Game> findAll() {
        List<Game> list = game.findAll();
        return list;
    }

    public List<ResultAccumulator> accumulator() {

        AccumulatorInitBuilder aib = ScriptOperators.accumulatorBuilder();

        AccumulatorInitArgsBuilder aiab = aib.init("function() {return { count: 0, sum: 0 }}");
        aib.lang("js");

        AccumulatorAccumulateArgsBuilder aaac = aiab
                .accumulate("function(state, score) { return {count: state.count + 1,sum: state.sum + score}}");
        List<Object> bl = new LinkedList<Object>();
        bl.add("score");

        AccumulatorMergeBuilder amb = aaac.accumulateArgs(bl);
        AccumulatorFinalizeBuilder afb = amb.merge(
                "function(state1, state2) {return {count: state1.count + state2.count,sum: state1.sum + state2.sum}}");
        // Accumulator a=afbb.build();
        Accumulator a = afb.finalize("function(state) {return (state.sum / state.count)}");

        Document document = a.toDocument();

        /*AggregationExpression expression = new AggregationExpression() {
            @Override
            public Document toDocument(AggregationOperationContext context) {
                Document document1 = document;
                return document1;
            }
        };
        Document document2 = expression.toDocument();*/
        
        GroupOperation groupByNameAndAccumulator = group("name").last(String.valueOf(document)).as("avgScore");
        Aggregation aggregation = newAggregation(groupByNameAndAccumulator);
        List<ResultAccumulator> results = mongoOperations
                .aggregate(aggregation, mongoTemplate.getCollectionName(Game.class), ResultAccumulator.class)
                .getMappedResults();
        // AggregationResults<ResultAccumulator> result =
        // mongoTemplate.aggregate(aggregation, "game", ResultAccumulator.class);
        System.out.println(document);
        System.out.println(results.toString());
        return results;
    }
}

这是打印包含累加器文档的服务器操作员,

2022-07-04 00:42:28.696  INFO 13784 --- [nio-8080-exec-2] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:3, serverValue:1531}] to localhost:27118
Document{{$accumulator=Document{{init=function() {return { count: 0, sum: 0 }}, accumulate=function(state, score) { return {count: state.count + 1,sum: state.sum + score}}, accumulateArgs=[score], merge=function(state1, state2) {return {count: state1.count + state2.count,sum: state1.sum + state2.sum}}, lang=js, finalize=function(state) {return (state.sum / state.count)}}}}}
[com.project.mongo.aggregation.ResultAccumulator@37517d96, com.project.mongo.aggregation.ResultAccumulator@19e6b063, com.project.emongo.aggregation.ResultAccumulator@3d69a1a5]

这是结果类,

import org.springframework.data.annotation.Id;

public class ResultAccumulator {
    @Id
    private String name;
    private Double avgScore;

    public ResultAccumulator() {
        super();
        // TODO Auto-generated constructor stub
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Double getAvgScore() {
        return avgScore;
    }
    public void setAvgScore(Double avgScore) {
        this.avgScore = avgScore;
    }
}

这是我不知道我在做什么的控制器

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.project.ecommercemongo.aggregation.ResultAccumulator;
import com.project.ecommercemongo.model.Game;
import com.project.ecommercemongo.service.GameService;
@RestController
@RequestMapping("/game")
public class GameController {
     @Autowired
       GameService service;
       
        @GetMapping("/find")
        public List<Game> listAll() {
            return service.findAll();
        }
        @GetMapping("/accumulator")
        public List<ResultAccumulator> accumulator() {
            return service.accumulator();
        }
}

,也许问题在对象累加器中。 再见,预先感谢您!

更新 现在它奏效了,我的错误是在小组中的最后一个方法上,现在我已经更改为累积(累加器)

       AccumulatorInitBuilder aib = ScriptOperators.accumulatorBuilder();

        AccumulatorInitArgsBuilder aiab = aib.init("function() {return { count: 0, sum: 0 }}");
        aib.lang("js");

        AccumulatorAccumulateArgsBuilder aaab = aiab
                .accumulate("function(state, score) { return {count: state.count + 1,sum: state.sum + score}}");
        List<Object> bl = new LinkedList<Object>();
        bl.add("$score");

        AccumulatorMergeBuilder amb = aaab.accumulateArgs(bl);
        AccumulatorFinalizeBuilder afb = amb.merge(
                "function(state1, state2) {return {count: state1.count + state2.count,sum: state1.sum + state2.sum}}");
        // Accumulator a=afbb.build();
        Accumulator a = afb.finalize("function(state) {return (state.sum / state.count)}");
        GroupOperation groupByNameAndAccumulator = group("name").accumulate(a).as("avgScore");
        Aggregation aggregation = newAggregation(groupByNameAndAccumulator);
        List<ResultAccumulator> results = mongoOperations
                .aggregate(aggregation, mongoTemplate.getCollectionName(Game.class), ResultAccumulator.class)
                .getMappedResults();
        // AggregationResults<ResultAccumulator> result =
        // mongoTemplate.aggregate(aggregation, "game", ResultAccumulator.class);
        return results;

public class ResultAccumulator {
   @Id
   private String name;
   private Float avgScore;
   public ResultAccumulator() {
      
    // TODO Auto-generated constructor stub
    }
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public Float getAvgScore() {
    return avgScore;
}
public void setAvgScore(float avgScore) {
    this.avgScore = avgScore;
}
    
}
[
    {
        "name": "Elizabeth",
        "avgScore": 10.0
    },
    {
        "name": "James ",
        "avgScore": 8.333333
    },
    {
        "name": "John",
        "avgScore": 8.333333
    }
]

I'm new in Spring-Data-MongoDB, I'm developing a method that performs MongoDB $accumulator operator in Spring-Data-MongoDB, but I don't know why my result on the $accumulator field return null.

Now I'm populating the collection in MongoDB:

db.game.insertMany([
{ "_id" : 1, "name" : "John", "score" : 10},
{ "_id" : 2, "name" : "Elizabeth", "score" : 10},
{ "_id" : 3, "name" : "James ", "score" : 9},
{ "_id" : 4, "name" : "John", "score" : 5},
{ "_id" : 5, "name" : "Elizabeth", "score" : 10},
{ "_id" : 6, "name" : "John", "score" : 10},
{ "_id" : 7, "name" : "Elizabeth", "score" : 10},
{ "_id" : 8, "name" : "James ", "score" : 8 },
{ "_id" : 9, "name" : "James ", "score" : 8}])

This is the accumulator aggregation in MongoDB Server:

db.game.aggregate ([
{
  $group :
  {
    _id : "$name",
    avgScore:
    {
      $accumulator:
      {
        init: function() {                        
          return { count: 0, sum: 0 }
        },
        accumulate: function(state, score) {                
          return {
            count: state.count + 1,
            sum: state.sum + score
          }
        },
        accumulateArgs: ["$score"],      
       
        merge: function(state1, state2) {        
          return {                              
            count: state1.count + state2.count,
            sum: state1.sum + state2.sum
          }
        },
        finalize: function(state) {               
          return (state.sum / state.count)       
        },
        lang: "js"
      }
    }
  }
}
])

This is the result of MongoDB that I'm trying to perform via Spring-Data-MongoDB:

{ "_id" : "Elizabeth", "avgScore" : 10 }
{ "_id" : "John", "avgScore" : 8.333333333333334 }
{ "_id" : "James ", "avgScore" : 8.333333333333334 }

This is the result of My RestController:

[
    {
        "name": "Elizabeth",
        "avgScore": null
    },
    {
        "name": "James ",
        "avgScore": null
    },
    {
        "name": "John",
        "avgScore": null
    }
]

this is the model Class

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
@Document(collection="game")
public class Game {
    @Id
    private Integer _id;
    private String name;
    private Integer score;
    public Game() {
        super();
        // TODO Auto-generated constructor stub
    }
    public int get_id() {
        return _id;
    }
    public void set_id(Integer _id) {
        this._id = _id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getScore() {
        return score;
    }
    public void setScore(Integer score) {
        this.score = score;
    }

}

This is the Service that performs the $accumulator operator on accumulator method, but it returns null:

import java.util.LinkedList;
import java.util.List;
import com.project.ecommercemongo.aggregation.ResultAccumulator;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationExpression;
import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;
import org.springframework.data.mongodb.core.aggregation.ScriptOperators;
import org.springframework.data.mongodb.core.aggregation.ScriptOperators.Accumulator;
import org.springframework.data.mongodb.core.aggregation.ScriptOperators.Accumulator.AccumulatorAccumulateArgsBuilder;
import org.springframework.data.mongodb.core.aggregation.ScriptOperators.Accumulator.AccumulatorFinalizeBuilder;
import org.springframework.data.mongodb.core.aggregation.ScriptOperators.Accumulator.AccumulatorInitArgsBuilder;
import org.springframework.data.mongodb.core.aggregation.ScriptOperators.Accumulator.AccumulatorInitBuilder;
import org.springframework.data.mongodb.core.aggregation.ScriptOperators.Accumulator.AccumulatorMergeBuilder;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.group;
import static org.springframework.data.mongodb.core.aggregation.Aggregation.newAggregation;
import org.springframework.stereotype.Service;
import org.springframework.data.mongodb.core.aggregation.GroupOperation;
import com.project.ecommercemongo.model.Game;
import com.project.ecommercemongo.repository.GameRepository;

@Service
public class GameService {
    @Autowired
    GameRepository game;
    @Autowired
    MongoTemplate mongoTemplate;
    @Autowired
    private MongoOperations mongoOperations;

    public List<Game> findAll() {
        List<Game> list = game.findAll();
        return list;
    }

    public List<ResultAccumulator> accumulator() {

        AccumulatorInitBuilder aib = ScriptOperators.accumulatorBuilder();

        AccumulatorInitArgsBuilder aiab = aib.init("function() {return { count: 0, sum: 0 }}");
        aib.lang("js");

        AccumulatorAccumulateArgsBuilder aaac = aiab
                .accumulate("function(state, score) { return {count: state.count + 1,sum: state.sum + score}}");
        List<Object> bl = new LinkedList<Object>();
        bl.add("score");

        AccumulatorMergeBuilder amb = aaac.accumulateArgs(bl);
        AccumulatorFinalizeBuilder afb = amb.merge(
                "function(state1, state2) {return {count: state1.count + state2.count,sum: state1.sum + state2.sum}}");
        // Accumulator a=afbb.build();
        Accumulator a = afb.finalize("function(state) {return (state.sum / state.count)}");

        Document document = a.toDocument();

        /*AggregationExpression expression = new AggregationExpression() {
            @Override
            public Document toDocument(AggregationOperationContext context) {
                Document document1 = document;
                return document1;
            }
        };
        Document document2 = expression.toDocument();*/
        
        GroupOperation groupByNameAndAccumulator = group("name").last(String.valueOf(document)).as("avgScore");
        Aggregation aggregation = newAggregation(groupByNameAndAccumulator);
        List<ResultAccumulator> results = mongoOperations
                .aggregate(aggregation, mongoTemplate.getCollectionName(Game.class), ResultAccumulator.class)
                .getMappedResults();
        // AggregationResults<ResultAccumulator> result =
        // mongoTemplate.aggregate(aggregation, "game", ResultAccumulator.class);
        System.out.println(document);
        System.out.println(results.toString());
        return results;
    }
}

This is the server that print the Document containing the accumulator operator,

2022-07-04 00:42:28.696  INFO 13784 --- [nio-8080-exec-2] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:3, serverValue:1531}] to localhost:27118
Document{{$accumulator=Document{{init=function() {return { count: 0, sum: 0 }}, accumulate=function(state, score) { return {count: state.count + 1,sum: state.sum + score}}, accumulateArgs=[score], merge=function(state1, state2) {return {count: state1.count + state2.count,sum: state1.sum + state2.sum}}, lang=js, finalize=function(state) {return (state.sum / state.count)}}}}}
[com.project.mongo.aggregation.ResultAccumulator@37517d96, com.project.mongo.aggregation.ResultAccumulator@19e6b063, com.project.emongo.aggregation.ResultAccumulator@3d69a1a5]

this is the Result Class

import org.springframework.data.annotation.Id;

public class ResultAccumulator {
    @Id
    private String name;
    private Double avgScore;

    public ResultAccumulator() {
        super();
        // TODO Auto-generated constructor stub
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Double getAvgScore() {
        return avgScore;
    }
    public void setAvgScore(Double avgScore) {
        this.avgScore = avgScore;
    }
}

this is the Controller

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.project.ecommercemongo.aggregation.ResultAccumulator;
import com.project.ecommercemongo.model.Game;
import com.project.ecommercemongo.service.GameService;
@RestController
@RequestMapping("/game")
public class GameController {
     @Autowired
       GameService service;
       
        @GetMapping("/find")
        public List<Game> listAll() {
            return service.findAll();
        }
        @GetMapping("/accumulator")
        public List<ResultAccumulator> accumulator() {
            return service.accumulator();
        }
}

I don't know what I'm doing wrong, maybe the problem is in the Object Accumulator .
Bye and thank you in advance!

Update
Now it work my mistake was on the method last in group,now i have changed to accumulate(Accumulator)

       AccumulatorInitBuilder aib = ScriptOperators.accumulatorBuilder();

        AccumulatorInitArgsBuilder aiab = aib.init("function() {return { count: 0, sum: 0 }}");
        aib.lang("js");

        AccumulatorAccumulateArgsBuilder aaab = aiab
                .accumulate("function(state, score) { return {count: state.count + 1,sum: state.sum + score}}");
        List<Object> bl = new LinkedList<Object>();
        bl.add("$score");

        AccumulatorMergeBuilder amb = aaab.accumulateArgs(bl);
        AccumulatorFinalizeBuilder afb = amb.merge(
                "function(state1, state2) {return {count: state1.count + state2.count,sum: state1.sum + state2.sum}}");
        // Accumulator a=afbb.build();
        Accumulator a = afb.finalize("function(state) {return (state.sum / state.count)}");
        GroupOperation groupByNameAndAccumulator = group("name").accumulate(a).as("avgScore");
        Aggregation aggregation = newAggregation(groupByNameAndAccumulator);
        List<ResultAccumulator> results = mongoOperations
                .aggregate(aggregation, mongoTemplate.getCollectionName(Game.class), ResultAccumulator.class)
                .getMappedResults();
        // AggregationResults<ResultAccumulator> result =
        // mongoTemplate.aggregate(aggregation, "game", ResultAccumulator.class);
        return results;

public class ResultAccumulator {
   @Id
   private String name;
   private Float avgScore;
   public ResultAccumulator() {
      
    // TODO Auto-generated constructor stub
    }
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public Float getAvgScore() {
    return avgScore;
}
public void setAvgScore(float avgScore) {
    this.avgScore = avgScore;
}
    
}
[
    {
        "name": "Elizabeth",
        "avgScore": 10.0
    },
    {
        "name": "James ",
        "avgScore": 8.333333
    },
    {
        "name": "John",
        "avgScore": 8.333333
    }
]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文