在spring mongo中使用条件运算符

时间:2017-06-09 11:43:00

标签: mongodb spring-data-mongodb

关注我的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数据代码。我打印了原始输出,碰巧得到了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"
        }
    ]
}

1 个答案:

答案 0 :(得分:0)

你正在使用(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");