Example usage for com.mongodb QueryOperators ELEM_MATCH

List of usage examples for com.mongodb QueryOperators ELEM_MATCH

Introduction

In this page you can find the example usage for com.mongodb QueryOperators ELEM_MATCH.

Prototype

String ELEM_MATCH

To view the source code for com.mongodb QueryOperators ELEM_MATCH.

Click Source Link

Usage

From source file:org.nuxeo.ecm.core.storage.mongodb.MongoDBQueryBuilder.java

License:Apache License

protected DBObject walkAnd(List<Operand> values) {
    List<Object> list = walkOperandList(values);
    // check wildcards in the operands, extract common prefixes to use $elemMatch
    Map<String, List<FieldInfoDBObject>> propBaseKeyToDBOs = new LinkedHashMap<>();
    Map<String, String> propBaseKeyToFieldBase = new HashMap<>();
    for (Iterator<Object> it = list.iterator(); it.hasNext();) {
        Object ob = it.next();/*  w  w w.  j  a v  a  2 s.c  om*/
        if (ob instanceof FieldInfoDBObject) {
            FieldInfoDBObject fidbo = (FieldInfoDBObject) ob;
            FieldInfo fieldInfo = fidbo.fieldInfo;
            if (fieldInfo.hasWildcard) {
                if (fieldInfo.fieldSuffix != null && fieldInfo.fieldSuffix.contains("*")) {
                    // a double wildcard of the form foo/*/bar/* is not a problem if bar is an array
                    // TODO prevent deep complex multiple wildcards
                    // throw new QueryParseException("Cannot use two wildcards: " + fieldInfo.prop);
                }
                // generate a key unique per correlation for this element match
                String wildcardNumber = fieldInfo.fieldWildcard;
                if (wildcardNumber.isEmpty()) {
                    // negative to not collide with regular correlated wildcards
                    wildcardNumber = String.valueOf(-counter.incrementAndGet());
                }
                String propBaseKey = fieldInfo.fieldPrefix + "/*" + wildcardNumber;
                // store object for this key
                List<FieldInfoDBObject> dbos = propBaseKeyToDBOs.get(propBaseKey);
                if (dbos == null) {
                    propBaseKeyToDBOs.put(propBaseKey, dbos = new LinkedList<>());
                }
                dbos.add(fidbo);
                // remember for which field base this is
                String fieldBase = fieldInfo.fieldPrefix.replace("/", ".");
                propBaseKeyToFieldBase.put(propBaseKey, fieldBase);
                // remove from list, will be re-added later through propBaseKeyToDBOs
                it.remove();
            }
        }
    }
    // generate $elemMatch items for correlated queries
    for (Entry<String, List<FieldInfoDBObject>> es : propBaseKeyToDBOs.entrySet()) {
        String propBaseKey = es.getKey();
        List<FieldInfoDBObject> fidbos = es.getValue();
        if (fidbos.size() == 1) {
            // regular uncorrelated match
            list.addAll(fidbos);
        } else {
            DBObject elemMatch = new BasicDBObject();
            for (FieldInfoDBObject fidbo : fidbos) {
                // truncate field name to just the suffix
                FieldInfo fieldInfo = fidbo.fieldInfo;
                Object value = fidbo.get(fieldInfo.queryField);
                String fieldSuffix = fieldInfo.fieldSuffix.replace("/", ".");
                if (elemMatch.containsField(fieldSuffix)) {
                    // ecm:acl/*1/principal = 'bob' AND ecm:acl/*1/principal = 'steve'
                    // cannot match
                    // TODO do better
                    value = "__NOSUCHVALUE__";
                }
                elemMatch.put(fieldSuffix, value);
            }
            String fieldBase = propBaseKeyToFieldBase.get(propBaseKey);
            BasicDBObject dbo = new BasicDBObject(fieldBase,
                    new BasicDBObject(QueryOperators.ELEM_MATCH, elemMatch));
            list.add(dbo);
        }
    }
    if (list.size() == 1) {
        return (DBObject) list.get(0);
    } else {
        return new BasicDBObject(QueryOperators.AND, list);
    }
}