【问题标题】:Using conditional operator in a spring mongo [duplicate]在spring mongo中使用条件运算符[重复]
【发布时间】:2017-06-09 11:42:59
【问题描述】:

按照我的 Mongo 查询

{$project:{
       id:"$_id",
       login:"$login",
       firstName: "$firstName",
       lastName:"$lastName",
       email:"$email",
       deactivateFlag:"$deactivateFlag",
       lastActivity:"$lastActivity",
       company :"$organization.name",
       RoleName :"$organization.roles.roleName",
       isMatchingRoles: { $eq: [ "$organization.roles.orgRoleId","$userOrgMap.roleId" ] }
      }
    },
    { $match: {isMatchingRoles:true},

这工作得很好。特别是最后一个 $match 可以完美地减少重复。但是当我尝试将上面的代码转换为等效的 Spring 数据时,我遇到了以下问题。

java.lang.IndexOutOfBoundsException: Index: 0, Size: 0 at java.util.ArrayList.rangeCheck(ArrayList.java:653) at java.util.ArrayList.get(ArrayList.java:429) at java.util.Collections$UnmodifiableList.get(Collections.java:‌​1309)

以下是我的 Spring Data 代码。我打印了原始输出,碰巧得到了 isMatchingRoles 的布尔值,它是我的 bean 类的一部分,在聚合期间映射。但是,当使用 getMappedResult 映射布尔值时,我遇到了这个问题。

aggregation = newAggregation(
                        match(getUsersCriteria(searchTxt)), 
                        unwind("userOrgMap"),
                        lookup("organizations", "userOrgMap.orgId", "_id", "organization"),
                        unwind("organization"),
                        unwind("organization.roles"),
    project("userId", "login", "firstName", "lastName", "email", "deactivateFlag", "lastActivity")
                                .and("organization.name").as("companyName")
                                .and("organization.roles.roleName").as("roleName")
                                .and(when(where("organization.roles.orgRoleId").is("userOrgMap.roleId")).then(true).otherwise(false)).as("isMatchingRoles"),
                            match(Criteria.where("isMatchingRoles").is(true))

    AggregationResults<UserDTO> groupResults groupResults = mongoOperation.aggregate(aggregation, UserDTO.class, UserDTO.class);
                    System.out.println(" Raw result "+groupResults.getMappedResults().get(0));
                    // The above result is getting data properly for isMatchingRoles

                    List<UserDTO> result = groupResults.getMappedResults();
                      // I am getting the exception in the above code

                    System.out.println(" actual mapped Reesult "+result.size());

以下是我的输入类

@Document(collection = "users")
public class UserDTO {



    @Id
    private String userId;
    private String login;
    private String firstName;
    private String lastName;
    private String lastActivity;
    private String email;
    private boolean deactivateFlag;
    private String companyName;
    private String roleName;
    private boolean isMatchingRoles;



    public UserDTO(String userId, String login, String firstName, String lastName, String lastActivity, String email,
            boolean deactivateFlag, String companyName, String roleName, boolean isMatchingRoles) {
        super();
        this.userId = userId;
        this.login = login;
        this.firstName = firstName;
        this.lastName = lastName;
        this.lastActivity = lastActivity;
        this.email = email;
        this.deactivateFlag = deactivateFlag;
        this.companyName = companyName;
        this.roleName = roleName;
        this.isMatchingRoles = isMatchingRoles;
    }


    public String getUserId() {
        return userId;
    }


    public void setUserId(String userId) {
        this.userId = userId;
    }


    public String getLogin() {
        return login;
    }


    public void setLogin(String login) {
        this.login = login;
    }


    public String getFirstName() {
        return firstName;
    }


    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }


    public String getLastName() {
        return lastName;
    }


    public void setLastName(String lastName) {
        this.lastName = lastName;
    }


    public String getLastActivity() {
        return lastActivity;
    }


    public void setLastActivity(String lastActivity) {
        this.lastActivity = lastActivity;
    }


    public String getEmail() {
        return email;
    }


    public void setEmail(String email) {
        this.email = email;
    }


    public boolean isDeactivateFlag() {
        return deactivateFlag;
    }


    public void setDeactivateFlag(boolean deactivateFlag) {
        this.deactivateFlag = deactivateFlag;
    }


    public String getCompanyName() {
        return companyName;
    }


    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }


    public String getRoleName() {
        return roleName;
    }


    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }


    public boolean isMatchingRoles() {
        return isMatchingRoles;
    }


    public void setMatchingRoles(boolean isMatchingRoles) {
        this.isMatchingRoles = isMatchingRoles;
    }



}

以下是我的样本集

user collection


{
    "_id" : "123",
    "login" : "abc@abc.com",
    "firstName" : "xxx",
    "lastName" : "yyy",
    "email" : "abc@abc.com",
    "deactivateFlag" : false,
    "userOrgMap" : [
        {
            "orgId" : "999",
            "roleId" : "888"
        }
    ]
}


Organization collection


{
    "_id" : "999",
    "name" : "orgName",
    "roles" : [
        {
            "orgRoleId" : "888",
            "roleName" : "Standard User"
        },
        {
            "orgRoleId" : "777",
            "roleName" : "Company Administrator"
        }
    ]
}

【问题讨论】:

  • 将输入和输出类都添加到帖子中。还有您使用 getMappedResult 方法的代码
  • 完成。请检查
  • organizationroles 的字段在哪里定义在 UserDTO 中?
  • 我已经提供了上面完整的API。组织是我查找的另一个集合。 Ogranization 是通过该查找创建的数组。
  • 您必须提供更多详细信息才能在我结束时重现该问题。我建议从您的所有集合中添加测试数据,并使用organizationroles 字段更新UserDTO

标签: mongodb spring-data-mongodb


【解决方案1】:

您正在使用(CriteriaDefinition) api(不知道为什么会在投影中暴露出来,可能是因为聚合运算符确实与查询运算符共享其某些功能)来生成条件表达式,该条件表达式应该用于正则查询表达式(用于$match 阶段和常规查找查询)。

条件定义 api 生成以下查询。

"isMatchingRoles": {
    "$cond": {
        "if": {
            "$eq": ["$organization.roles.orgRoleId", "userOrgMap.roleId"]
        },
        "then": true,
        "else": false
    }
} 

注意$eq 的第二个参数是字符串值而不是字段引用。

您可以通过以下两种方式做到这一点。

使用ConditonalOperator api。

.and(when(ComparisonOperators.Eq.valueOf("organization.roles.orgRoleId").equalTo("userOrgMap.roleId")).then(true).otherwise(false)).as("isMatchingRoles")

使用AggregationExpression 生成条件表达式。

and(new AggregationExpression() {
            @Override
            public DBObject toDbObject(AggregationOperationContext context) {
                return new BasicDBObject("$cond",
                        Arrays.<Object>asList(
                                new BasicDBObject("$eq", 
                                        Arrays.asList("$organization.roles.orgRoleId", "$userOrgMap.roleId")),
                                true,
                                false));
            }
 }).as("isMatchingRoles");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-21
    • 1970-01-01
    • 2021-04-22
    • 2019-06-15
    • 2014-08-09
    • 2018-03-21
    • 2020-01-07
    • 1970-01-01
    相关资源
    最近更新 更多