我正在Spring Data MongoDB中开发一个方法,它使用$facet、$addFields和$function,但返回null.

这是MongoDB中的聚合

db.utenti.aggregate([
    {
        $facet:
        {
            "aggregation": [
                  {
                    $match: { age: { $gt: 18 } }
                },
                {
                    $addFields:{
                        max: {
                            $function: {
                               body: function(name, scores) {
                                  let max = Math.max(...scores);
                                  return `Hello ${name}.  Your max score is ${max}.`
                               },
                               args: [ "$name", "$scores"],
                               lang: "js"
                            }    
                        }
                      
                    }
                }
            ]
        }
    }
]).pretty()

这是预期结果

{
        "aggregation" : [
                {
                        "_id" : ObjectId("62c5f16b39b3d635ab6bf60d"),
                        "username" : "james34",
                        "name" : "james",
                        "role" : [
                                "user",
                                "specialuser"
                        ],
                        "age" : 34,
                        "scores" : [
                                10,
                                9,
                                10
                        ],
                        "_class" : "com.project.ecommercemongo.model.User",
                        "max" : "Hello james.  Your max score is 10."
                },
                {
                        "_id" : ObjectId("62c5f1b839b3d635ab6bf60e"),
                        "username" : "elizabeth54",
                        "name" : "elizabeth",
                        "role" : [
                                "user",
                                "specialuser"
                        ],
                        "age" : 54,
                        "scores" : [
                                10,
                                10,
                                10
                        ],
                        "_class" : "com.project.ecommercemongo.model.User",
                        "max" : "Hello elizabeth.  Your max score is 10."
                },
                {
                        "_id" : ObjectId("62c5f1f139b3d635ab6bf60f"),
                        "username" : "frank50",
                        "name" : "frank",
                        "role" : [
                                "user"
                        ],
                        "age" : 50,
                        "scores" : [
                                10,
                                10,
                                10
                        ],
                        "_class" : "com.project.ecommercemongo.model.User",
                        "max" : "Hello frank.  Your max score is 10."
                },
                {
                        "_id" : ObjectId("62c5f27a39b3d635ab6bf610"),
                        "username" : "john26",
                        "name" : "john",
                        "role" : [
                                "user"
                        ],
                        "age" : 26,
                        "scores" : [
                                8,
                                8,
                                10
                        ],
                        "_class" : "com.project.ecommercemongo.model.User",
                        "max" : "Hello john.  Your max score is 10."
                }
        ]
}

这是我得到的结果

[
    {
        "_id": null,
        "username": null,
        "name": null,
        "role": null,
        "age": null,
        "scores": null
    }
]

这是一个调用方面addFields和函数的方法,但它不添加字段"max",并返回null

public List<User> aggregation1() {
        List<Object> bl = new LinkedList<Object>();
        bl.add("$name");
        bl.add("$scores");
        ScriptOperators.Function function= Function.function("function(name, scores) {let max = Math.max(...scores); return `Hello ${name}.  Your max score is ${max}`}").args(bl).lang("js");//`Hello ${name}.  Your max score is ${max}.`}");
        System.out.println(function.toDocument());
        FacetOperation facetOperation1 = Aggregation.facet(Aggregation.match(Criteria.where("age").gte(18)),Aggregation.addFields().addFieldWithValue("max", function).build()).as("aggregation");
        Aggregation agg = Aggregation.newAggregation(facetOperation1);
        return mongoTemplate.aggregate(agg, "utenti",User.class).getMappedResults();
    }

这是用户类

@Document(collection="utenti")
//@Sharded(shardKey = { "country", "userId" }) 
public class User {

    @Id
    private String _id;
    private String username;
    private String name;
    private String[] role;
    private Integer age;
    private Integer[] scores;
   


    public User() {
        super();
    }

    public String get_id() {
        return _id;
    }

    public void set_id(String _id) {
        this._id = _id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String[] getRole() {
        return role;
    }

    public void setRole(String[] role) {
        this.role = role;
    }
    
    public Integer[] getScores() {
        return scores;
    }

    public void setScores(Integer[] scores) {
        this.scores = scores;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    
}

如何将所有用户放入方面并添加字段?非常感谢.

Update

public List<MaxFacet> aggregation1() {

        List<Object> bl = new LinkedList<Object>();
        bl.add("$name");
        bl.add("$scores");
        ScriptOperators.Function function = Function.function(
                "function(name, scores) {let max = Math.max(...scores); return `Hello ${name}.  Your max score is ${max}.`}")
                .args(bl).lang("js");// `Hello ${name}. Your max score is ${max}.`}");
        System.out.println(function.toDocument());
        FacetOperation facetOperation = Aggregation.facet().and(match(Criteria.where("age").gte(18)),
                Aggregation.addFields().addFieldWithValue("max", function).build()).as("aggregation");
        Aggregation agg = Aggregation.newAggregation(facetOperation);

        return mongoOperations.aggregate(agg, mongoTemplate.getCollectionName(User.class), MaxFacet.class)
                .getMappedResults();

    }
public class MaxFacet {
    
        private List<UserOut> aggregation;

        public List<UserOut> getAggregation() {
            return aggregation;
        }
        public void setAggregation(List<UserOut> facet1) {
            this.aggregation = facet1;
        }
        public MaxFacet() {
            
            // TODO Auto-generated constructor stub
        }
}
@JsonPropertyOrder({"id","username","name","age","scores","max"})
public class UserOut {
    @JsonProperty(value="id")
    private String id;
    private String username;
    private String name;
    private String []scores;
    private String max;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String[] getScores() {
        return scores;
    }
    public void setScores(String[] scores) {
        this.scores = scores;
    }
    public String getMax() {
        return max;
    }
    public void setMax(String value) {
        this.max= value;
    }
    
}
[
    {
        "aggregation": [
            {
                "id": "62c5f16b39b3d635ab6bf60d",
                "username": "james34",
                "name": "james",
                "scores": [
                    "10",
                    "9",
                    "10"
                ],
                "max": "Hello james.  Your max score is 10."
            },
            {
                "id": "62c5f1b839b3d635ab6bf60e",
                "username": "elizabeth54",
                "name": "elizabeth",
                "scores": [
                    "10",
                    "10",
                    "10"
                ],
                "max": "Hello elizabeth.  Your max score is 10."
            },
            {
                "id": "62c5f1f139b3d635ab6bf60f",
                "username": "frank50",
                "name": "frank",
                "scores": [
                    "10",
                    "10",
                    "10"
                ],
                "max": "Hello frank.  Your max score is 10."
            },
            {
                "id": "62c5f27a39b3d635ab6bf610",
                "username": "john26",
                "name": "john",
                "scores": [
                    "8",
                    "8",
                    "10"
                ],
                "max": "Hello john.  Your max score is 10."
            }
        ]
    }
]

推荐答案

Alternative soluition:你可以用这种方法来simplify你的代码

1-UserOut级使用inheritance mecanism

public class UserOut extends User {
    private String max;

    public String getMax() {
        return max;
    }
    public void setMax(String value) {
        this.max= value;
    }
}

2-对于复杂的管道,custom AggregationOperation实现比Spring Data builder更友好.

AggregationOperation facetOperation = ao -> 
    new Document("$facet", 
        new Document("aggregation", Arrays.asList(
            new Document("$match", new Document("age", new Document("$gt", 18))),
            new Document("$addFields", 
                new Document("max", 
                    new Document("$function", 
                        new Document("body", "function(name, scores) {"+
                                             "  let max = Math.max(...scores);"+
                                             "  return `Hello ${name}.  Your max score is ${max}.`"+
                                             "}")
                            .append("args", Arrays.asList("$name", "$scores"))
                            .append("lang", "js")
                    )
                )
            )
        ))
    );

Aggregation agg = Aggregation.newAggregation(facetOperation);
return mongoOperations
    .aggregate(agg, mongoTemplate.getCollectionName(User.class), MaxFacet.class)
    .getMappedResults();

或者,只需以这种方式解析shell JSON查询(从Java 13开始的三重引号):

Document.parse("""
{
    "$facet":
    {
        "aggregation": [
              {
                "$match": { "age": { "$gt": 18 } }
            },
            {
                "$addFields":{
                    "max": {
                        "$function": {
                           "body": function(name, scores) {
                              let max = Math.max(...scores);
                              return `Hello ${name}.  Your max score is ${max}.`
                           },
                           "args": [ "$name", "$scores"],
                           "lang": "js"
                        }    
                    }
                  
                }
            }
        ]
    }
}
""")

Mongodb相关问答推荐

使用MongoDB 4将根文档替换为数组

如何使用mongodb进行离线开发?

使用mongo'db.Decode(&dto)映射一个嵌套的 struct

如何从集合中移除所有匹配的数组项?

将 MongoDB BsonDocument 转换为字符串

如何在 MongoDB 中存储时间?作为字符串?给出任意年/月/日?

使用 AngularJs 和 MongoDB/Mongoose

MongoDB 更改流副本集限制

使用模拟 MongoDB 服务器进行单元测试

$lookup 结果 mongodb 的计数

在 Mongoid 中,Date、Time、DateTime 和 TimeWithZone 字段类型有什么区别吗?

Mongoose 中不同集合的相同模式

如何在mongoose中加入两个集合

无法连接到远程 mongodb 服务器

Mongoose.pre('save') 不会触发

MongoDB:如何在 100 个集合中找到 10 个随机文档?

Mongoose 版本控制:when is it safe to disable it?

Mongodb 按字段名称查找任何值

Mongodb同时在多个字段上聚合(计数)

创建模型时出现mongoose错误