diff --git a/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/domain/CriterionOperator.java b/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/domain/CriterionOperator.java
index dade63f31cba2fc9325e570f4a7ddedf2951aee8..0afca9835701b02059958c51838bf245f6fcd81c 100644
--- a/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/domain/CriterionOperator.java
+++ b/commons/commons-api/src/main/java/fr/gouv/vitamui/commons/api/domain/CriterionOperator.java
@@ -49,5 +49,6 @@ public enum CriterionOperator {
     CONTAINS,
     CONTAINSIGNORECASE,
     BETWEEN,
-    STARTWITH;
+    STARTWITH,
+    ELEMMATCH
 }
diff --git a/commons/commons-mongo/src/main/java/fr/gouv/vitamui/commons/mongo/utils/MongoUtils.java b/commons/commons-mongo/src/main/java/fr/gouv/vitamui/commons/mongo/utils/MongoUtils.java
index 4b6f344e437bfc1574c2b409d436444b83b269ac..740963ba893f204ff40a93d640ed52253231e69f 100644
--- a/commons/commons-mongo/src/main/java/fr/gouv/vitamui/commons/mongo/utils/MongoUtils.java
+++ b/commons/commons-mongo/src/main/java/fr/gouv/vitamui/commons/mongo/utils/MongoUtils.java
@@ -39,6 +39,7 @@ package fr.gouv.vitamui.commons.mongo.utils;
 import java.lang.reflect.Type;
 import java.time.Duration;
 import java.time.OffsetDateTime;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
@@ -46,6 +47,9 @@ import java.util.Optional;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
+import fr.gouv.vitamui.commons.api.domain.QueryDto;
+import fr.gouv.vitamui.commons.api.domain.QueryOperator;
+import fr.gouv.vitamui.commons.utils.JsonUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.data.mongodb.core.query.Criteria;
 import org.springframework.data.mongodb.core.query.CriteriaDefinition;
@@ -185,6 +189,8 @@ public final class MongoUtils {
                 mapValue.put(BETWEEN_OPERATOR_KEY_START, convertValue(parametrizedClazz, mapValue.get(BETWEEN_OPERATOR_KEY_START)));
                 mapValue.put(BETWEEN_OPEARTOR_KEY_END, convertValue(parametrizedClazz, mapValue.get(BETWEEN_OPEARTOR_KEY_END)));
                 return mapValue;
+            case ELEMMATCH:
+                return convertValue(QueryDto.class, value);
             default :
                 return convertValue(parametrizedClazz, value);
         }
@@ -209,6 +215,14 @@ public final class MongoUtils {
             return Boolean.parseBoolean(value.toString());
         } else if (VitamUIUtils.canBeCastByClass(value, List.class)) {
             return value;
+        } else if (clazz.equals(QueryDto.class)) {
+            try {
+                // we convert the linked hash map to json to re-convert it properly to query dto
+                return QueryDto.fromJson(JsonUtils.toJson(value));
+            }
+            catch (Exception e) {
+                throw new InvalidFormatException(e.getMessage(), e);
+            }
         }
 
         return CastUtils.castValue(value, clazz);
@@ -275,12 +289,36 @@ public final class MongoUtils {
                 final Criteria endCriteria = Criteria.where(key).lte(mapVal.get(BETWEEN_OPEARTOR_KEY_END));
                 criteria = buildAndOperator(startCriteria, endCriteria);
                 break;
+            case ELEMMATCH :
+                criteria = Criteria.where(key).elemMatch(queryDTOToCriterion((QueryDto)val));
+                break;
             default :
                 throw new IllegalArgumentException("Operator " + operator + " is not supported");
         }
         return criteria;
     }
 
+    public static Criteria queryDTOToCriterion(QueryDto queryDto) {
+        Collection<CriteriaDefinition> criteria = new ArrayList<>();
+        queryDto.getCriterionList().forEach(criterion -> {
+            criteria.add(MongoUtils.getCriteria(criterion.getKey(), criterion.getValue(), criterion.getOperator()));
+        });
+
+        // if the criteria contains subQueries, a recursive call is made for each subQuery
+        queryDto.getSubQueries().forEach(queryDtoItem -> {
+            criteria.add(queryDTOToCriterion(queryDtoItem));
+        });
+
+        final Criteria commonCustomCriteria = new Criteria();
+        if (queryDto.getQueryOperator() == QueryOperator.AND) {
+            commonCustomCriteria.andOperator(criteria.stream().map(c -> (Criteria) c).toArray(Criteria[]::new));
+        } else if (queryDto.getQueryOperator() == QueryOperator.OR) {
+            commonCustomCriteria.orOperator(criteria.stream().map(c -> (Criteria) c).toArray(Criteria[]::new));
+        }
+        return commonCustomCriteria;
+    }
+
+
     public static Type getTypeOfField(final Class<?> entityClass, final String fieldName) {
         try {
             return ReflectionUtils.getTypeOfField(entityClass, fieldName);