diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 60bc720bc15742202308679282562c5aede6c951..72a02bb52c2be573baee3f2c4f01e9c6680183a3 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -16,7 +16,7 @@ run_tests:
       junit: report.xml
 
 lint:
-  image: golangci/golangci-lint:v1.55-alpine
+  image: golangci/golangci-lint:v1.56-alpine
   rules:
     - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH)'
   stage: test
diff --git a/go.mod b/go.mod
index c1c371718e1900db44be42b040fd4d19424ce424..81d914bcbb61d73aadf2c8c1851bff6f660d05b5 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module git.perx.ru/perxis/perxis-go
 
-go 1.21
+go 1.22
 
 require (
 	github.com/avast/retry-go/v4 v4.5.1
diff --git a/pkg/expr/mongo.go b/pkg/expr/mongo.go
index 597180a671e80c2a5bc79bb8efd9bbee940120e4..566dc6366c13ecfd809fbfc37dfd82d2f0df5fa3 100644
--- a/pkg/expr/mongo.go
+++ b/pkg/expr/mongo.go
@@ -20,15 +20,22 @@ var geoTypes = map[string]string{
 	"polygon": "$polygon",
 }
 
-func ConvertToMongo(ctx context.Context, exp string, env map[string]interface{}, identifierRenameFn func(string) string, ops ...expr.Option) (b bson.M, err error) {
-	if exp == "" {
+type MongoExprConfig struct {
+	Env                map[string]any
+	IdentifierRenameFn func(s string) string
+	Ops                []expr.Option
+}
+
+func ConvertToMongo(ctx context.Context, config *MongoExprConfig, exprs ...string) (b bson.M, err error) {
+	if len(exprs) == 0 {
 		return bson.M{}, nil
 	}
+	exp := "(" + strings.Join(exprs, ") && (") + ")"
 	tree, err := parser.Parse(exp)
 	if err != nil {
 		return nil, err
 	}
-	return convertToMongo(ctx, tree, env, identifierRenameFn, ops...)
+	return convertToMongo(ctx, tree, config.Env, config.IdentifierRenameFn, config.Ops...)
 }
 
 func convertToMongo(ctx context.Context, tree *parser.Tree, env map[string]interface{}, identifierRenameFn func(string) string, ops ...expr.Option) (b bson.M, err error) {
diff --git a/pkg/expr/mongo_test.go b/pkg/expr/mongo_test.go
index dee6e668c490a6d375a77c532862f5389b1bd5f4..5304b9cdb4f17d95b43008efa57a3169f37ef18b 100644
--- a/pkg/expr/mongo_test.go
+++ b/pkg/expr/mongo_test.go
@@ -22,65 +22,69 @@ func TestConvertToMongo(t *testing.T) {
 
 	tests := []struct {
 		name    string
-		eval    string
+		eval    []string
 		env     map[string]interface{}
 		wantB   bson.M
 		wantErr bool
 	}{
-		{"equal", "s == 3", nil, bson.M{"s": 3}, false},
-		{"in array", "s in [1,2,3]", nil, bson.M{"s": bson.M{"$in": []interface{}{1, 2, 3}}}, false},
-		{"not in array", "s not in [1,2,3]", nil, bson.M{"s": bson.M{"$nin": []interface{}{1, 2, 3}}}, false},
-		{"exists#1", "exists(s)", nil, bson.M{"s": bson.M{"$exists": true}}, false},
-		{"exists#2", "exists(s, s)", nil, nil, true},
-		{"len#1", "len(s)", nil, nil, true},
-		{"len#2", "len(s) <> 1", nil, nil, true},
-		{"len#3", "len(s) == -1", nil, nil, true},
-		{"len#4", "len(s, s) == -1", nil, nil, true},
-		{"len#5", "len(s) == s", nil, nil, true},
-		{"len eq", "len(s) == 1", nil, bson.M{"s": bson.M{"$size": 1}}, false},
-		{"len eq zero", "len(s) == 0", nil, bson.M{"s": bson.M{"$eq": bson.A{}}}, false},
-		{"len ne", "len(s) != 1", nil, bson.M{"s": bson.M{"$not": bson.M{"$size": 1}, "$type": "array"}}, false},
-		{"len ne zero", "len(s) != 0", nil, bson.M{"s": bson.M{"$exists": true, "$ne": bson.A{}, "$type": "array"}}, false},
-		{"len gt", "len(s) > 1", nil, bson.M{"s.1": bson.M{"$exists": true}}, false},
-		{"len gt zero", "len(s) > 0", nil, bson.M{"s": bson.M{"$exists": true, "$type": "array", "$ne": bson.A{}}}, false},
-		{"len gte", "len(s) >= 1", nil, bson.M{"s.0": bson.M{"$exists": true}}, false},
-		{"len gte zero", "len(s) >= 0", nil, bson.M{"s": bson.M{"$exists": true, "$type": "array"}}, false},
-		{"len lt", "len(s) < 1", nil, bson.M{"s.0": bson.M{"$exists": false}, "s": bson.M{"$type": "array"}}, false},
-		{"len lt zero", "len(s) < 0", nil, nil, true},
-		{"len lte", "len(s) <= 1", nil, bson.M{"s.1": bson.M{"$exists": false}, "s": bson.M{"$type": "array"}}, false},
-		{"len lte zero", "len(s) <= 0", nil, bson.M{"s": bson.M{"$eq": bson.A{}}}, false},
-		{"field#1", "s.test > 3", nil, bson.M{"s.test": bson.M{"$gt": 3}}, false},
-		{"field#2", "s['test'] > 3", nil, bson.M{"s.test": bson.M{"$gt": 3}}, false},
-		{"field#3", "s[test] > 3", nil, bson.M{"s.test": bson.M{"$gt": 3}}, false},
-		{"contains", "s contains 'some'", nil, bson.M{"s": bson.M{"$regex": "some"}}, false},
-		{"contains with . + () $ {} ^", "value contains 'something with . + () $ {} ^'", nil, bson.M{"value": bson.M{"$regex": "something with \\. \\+ \\(\\) \\$ \\{\\} \\^"}}, false},
-		{"startsWith", "s startsWith 'some'", nil, bson.M{"s": bson.M{"$regex": "^some.*"}}, false},
-		{"startsWith . + () $ {} ^", "s startsWith '. + () $ {} ^'", nil, bson.M{"s": bson.M{"$regex": "^\\. \\+ \\(\\) \\$ \\{\\} \\^.*"}}, false},
-		{"endsWith", "s endsWith 'some'", nil, bson.M{"s": bson.M{"$regex": ".*some$"}}, false},
-		{"endsWith . + () $ {} ^", "s endsWith '. + () $ {} ^'", nil, bson.M{"s": bson.M{"$regex": ".*\\. \\+ \\(\\) \\$ \\{\\} \\^$"}}, false},
-		{"icontains", "icontains(s, 'some')", nil, bson.M{"s": bson.M{"$regex": "some", "$options": "i"}}, false},
-		{"icontains with . + () $ {} ^", "icontains (value, 'something with . + () $ {} ^')", nil, bson.M{"value": bson.M{"$regex": "something with \\. \\+ \\(\\) \\$ \\{\\} \\^", "$options": "i"}}, false},
-		{"istartsWith", "istartsWith(s, 'Some')", nil, bson.M{"s": bson.M{"$regex": "^Some.*", "$options": "i"}}, false},
-		{"istartsWith . + () $ {} ^ . + () $ {} ^", "istartsWith(s, '. + () $ {} ^')", nil, bson.M{"s": bson.M{"$regex": "^\\. \\+ \\(\\) \\$ \\{\\} \\^.*", "$options": "i"}}, false},
-		{"iendsWith", "iendsWith(s, 'some')", nil, bson.M{"s": bson.M{"$regex": ".*some$", "$options": "i"}}, false},
-		{"iendsWith . + () $ {} ^", "iendsWith(s,'. + () $ {} ^')", nil, bson.M{"s": bson.M{"$regex": ".*\\. \\+ \\(\\) \\$ \\{\\} \\^$", "$options": "i"}}, false},
-		{"or", "s==2 || s > 10", nil, bson.M{"$or": bson.A{bson.M{"s": 2}, bson.M{"s": bson.M{"$gt": 10}}}}, false},
-		{"not#1", "not icontains(s, 'some')", nil, bson.M{"$nor": bson.A{bson.M{"s": bson.M{"$options": "i", "$regex": "some"}}}}, false},
-		{"not#2", "not (s.test > 3)", nil, bson.M{"$nor": bson.A{bson.M{"s.test": bson.M{"$gt": 3}}}}, false},
-		{"search", "search('some') || s > 10", nil, bson.M{"$or": bson.A{bson.M{"$text": bson.M{"$search": "some"}}, bson.M{"s": bson.M{"$gt": 10}}}}, false},
-		{"vars:or", "s== a + 2 || s > a + 10", map[string]interface{}{"a": 100}, bson.M{"$or": bson.A{bson.M{"s": 102}, bson.M{"s": bson.M{"$gt": 110}}}}, false},
-		{"near", "near(a, [55.5, 37.5], 1000)", map[string]interface{}{"a": []interface{}{55, 37}}, bson.M{"a.geometry": bson.M{"$near": bson.D{{Key: "$geometry", Value: map[string]interface{}{"coordinates": []interface{}{55.5, 37.5}, "type": "Point"}}, {Key: "$maxDistance", Value: 1000}}}}, false},
-		{"within", "within(a, 'box', [[54.54, 36.36], [55.55, 37.37]])", map[string]interface{}{"a": []interface{}{55, 37}}, bson.M{"a.geometry": bson.M{"$geoWithin": bson.M{"$box": []interface{}{[]interface{}{54.54, 36.36}, []interface{}{55.55, 37.37}}}}}, false},
-		{"time", "d > Time.Date('2021-08-31')", nil, bson.M{"d": bson.M{"$gt": dt}}, false},
-		{"time", fmt.Sprintf("d > Time.Time('%s')", now.Format(time.RFC3339)), nil, bson.M{"d": bson.M{"$gt": tm}}, false},
-		{"in", "In(s, [1,2,3])", nil, bson.M{"s": bson.M{"$in": []interface{}{1, 2, 3}}}, false},
-		{"in", "In(s, 1)", nil, bson.M{"s": bson.M{"$in": []interface{}{1}}}, false},
-		{"text search or id", "id", nil, nil, true},
-		{"struct env", "db_item.id == env_item.id", map[string]interface{}{"env_item": &testEnvStruct{ID: "id1"}}, bson.M{"db_item.id": "id1"}, false},
+		{"equal", []string{"s == 3"}, nil, bson.M{"s": 3}, false},
+		{"equal (with []string)", []string{"object.space_id == 'sp'", "object.organization_id == 'org'"}, nil, bson.M{"$and": bson.A{bson.M{"object.space_id": "sp"}, bson.M{"object.organization_id": "org"}}}, false},
+		{"equal (with nil []string)", nil, nil, bson.M{}, false},
+		{"in array", []string{"s in [1,2,3]"}, nil, bson.M{"s": bson.M{"$in": []interface{}{1, 2, 3}}}, false},
+		{"not in array", []string{"s not in [1,2,3]"}, nil, bson.M{"s": bson.M{"$nin": []interface{}{1, 2, 3}}}, false},
+		{"exists#1", []string{"exists(s)"}, nil, bson.M{"s": bson.M{"$exists": true}}, false},
+		{"exists#2", []string{"exists(s, s)"}, nil, nil, true},
+		{"len#1", []string{"len(s)"}, nil, nil, true},
+		{"len#2", []string{"len(s) <> 1"}, nil, nil, true},
+		{"len#3", []string{"len(s) == -1"}, nil, nil, true},
+		{"len#4", []string{"len(s, s) == -1"}, nil, nil, true},
+		{"len#5", []string{"len(s) == s"}, nil, nil, true},
+		{"len eq", []string{"len(s) == 1"}, nil, bson.M{"s": bson.M{"$size": 1}}, false},
+		{"len eq zero", []string{"len(s) == 0"}, nil, bson.M{"s": bson.M{"$eq": bson.A{}}}, false},
+		{"len ne", []string{"len(s) != 1"}, nil, bson.M{"s": bson.M{"$not": bson.M{"$size": 1}, "$type": "array"}}, false},
+		{"len ne zero", []string{"len(s) != 0"}, nil, bson.M{"s": bson.M{"$exists": true, "$ne": bson.A{}, "$type": "array"}}, false},
+		{"len gt", []string{"len(s) > 1"}, nil, bson.M{"s.1": bson.M{"$exists": true}}, false},
+		{"len gt zero", []string{"len(s) > 0"}, nil, bson.M{"s": bson.M{"$exists": true, "$type": "array", "$ne": bson.A{}}}, false},
+		{"len gte", []string{"len(s) >= 1"}, nil, bson.M{"s.0": bson.M{"$exists": true}}, false},
+		{"len gte zero", []string{"len(s) >= 0"}, nil, bson.M{"s": bson.M{"$exists": true, "$type": "array"}}, false},
+		{"len lt", []string{"len(s) < 1"}, nil, bson.M{"s.0": bson.M{"$exists": false}, "s": bson.M{"$type": "array"}}, false},
+		{"len lt zero", []string{"len(s) < 0"}, nil, nil, true},
+		{"len lte", []string{"len(s) <= 1"}, nil, bson.M{"s.1": bson.M{"$exists": false}, "s": bson.M{"$type": "array"}}, false},
+		{"len lte zero", []string{"len(s) <= 0"}, nil, bson.M{"s": bson.M{"$eq": bson.A{}}}, false},
+		{"field#1", []string{"s.test > 3"}, nil, bson.M{"s.test": bson.M{"$gt": 3}}, false},
+		{"field#2", []string{"s['test'] > 3"}, nil, bson.M{"s.test": bson.M{"$gt": 3}}, false},
+		{"field#3", []string{"s[test] > 3"}, nil, bson.M{"s.test": bson.M{"$gt": 3}}, false},
+		{"contains", []string{"s contains 'some'"}, nil, bson.M{"s": bson.M{"$regex": "some"}}, false},
+		{"contains with . + () $ {} ^", []string{"value contains 'something with . + () $ {} ^'"}, nil, bson.M{"value": bson.M{"$regex": "something with \\. \\+ \\(\\) \\$ \\{\\} \\^"}}, false},
+		{"startsWith", []string{"s startsWith 'some'"}, nil, bson.M{"s": bson.M{"$regex": "^some.*"}}, false},
+		{"startsWith . + () $ {} ^", []string{"s startsWith '. + () $ {} ^'"}, nil, bson.M{"s": bson.M{"$regex": "^\\. \\+ \\(\\) \\$ \\{\\} \\^.*"}}, false},
+		{"endsWith", []string{"s endsWith 'some'"}, nil, bson.M{"s": bson.M{"$regex": ".*some$"}}, false},
+		{"endsWith . + () $ {} ^", []string{"s endsWith '. + () $ {} ^'"}, nil, bson.M{"s": bson.M{"$regex": ".*\\. \\+ \\(\\) \\$ \\{\\} \\^$"}}, false},
+		{"icontains", []string{"icontains(s, 'some')"}, nil, bson.M{"s": bson.M{"$regex": "some", "$options": "i"}}, false},
+		{"icontains with . + () $ {} ^", []string{"icontains (value, 'something with . + () $ {} ^')"}, nil, bson.M{"value": bson.M{"$regex": "something with \\. \\+ \\(\\) \\$ \\{\\} \\^", "$options": "i"}}, false},
+		{"istartsWith", []string{"istartsWith(s, 'Some')"}, nil, bson.M{"s": bson.M{"$regex": "^Some.*", "$options": "i"}}, false},
+		{"istartsWith . + () $ {} ^ . + () $ {} ^", []string{"istartsWith(s, '. + () $ {} ^')"}, nil, bson.M{"s": bson.M{"$regex": "^\\. \\+ \\(\\) \\$ \\{\\} \\^.*", "$options": "i"}}, false},
+		{"iendsWith", []string{"iendsWith(s, 'some')"}, nil, bson.M{"s": bson.M{"$regex": ".*some$", "$options": "i"}}, false},
+		{"iendsWith . + () $ {} ^", []string{"iendsWith(s,'. + () $ {} ^')"}, nil, bson.M{"s": bson.M{"$regex": ".*\\. \\+ \\(\\) \\$ \\{\\} \\^$", "$options": "i"}}, false},
+		{"or", []string{"s==2 || s > 10"}, nil, bson.M{"$or": bson.A{bson.M{"s": 2}, bson.M{"s": bson.M{"$gt": 10}}}}, false},
+		{"not#1", []string{"not icontains(s, 'some')"}, nil, bson.M{"$nor": bson.A{bson.M{"s": bson.M{"$options": "i", "$regex": "some"}}}}, false},
+		{"not#2", []string{"not (s.test > 3)"}, nil, bson.M{"$nor": bson.A{bson.M{"s.test": bson.M{"$gt": 3}}}}, false},
+		{"search", []string{"search('some') || s > 10"}, nil, bson.M{"$or": bson.A{bson.M{"$text": bson.M{"$search": "some"}}, bson.M{"s": bson.M{"$gt": 10}}}}, false},
+		{"vars:or", []string{"s== a + 2 || s > a + 10"}, map[string]interface{}{"a": 100}, bson.M{"$or": bson.A{bson.M{"s": 102}, bson.M{"s": bson.M{"$gt": 110}}}}, false},
+		{"near", []string{"near(a, [55.5, 37.5], 1000)"}, map[string]interface{}{"a": []interface{}{55, 37}}, bson.M{"a.geometry": bson.M{"$near": bson.D{{Key: "$geometry", Value: map[string]interface{}{"coordinates": []interface{}{55.5, 37.5}, "type": "Point"}}, {Key: "$maxDistance", Value: 1000}}}}, false},
+		{"within", []string{"within(a, 'box', [[54.54, 36.36], [55.55, 37.37]])"}, map[string]interface{}{"a": []interface{}{55, 37}}, bson.M{"a.geometry": bson.M{"$geoWithin": bson.M{"$box": []interface{}{[]interface{}{54.54, 36.36}, []interface{}{55.55, 37.37}}}}}, false},
+		{"time", []string{"d > Time.Date('2021-08-31')"}, nil, bson.M{"d": bson.M{"$gt": dt}}, false},
+		{"time", []string{fmt.Sprintf("d > Time.Time('%s')", now.Format(time.RFC3339))}, nil, bson.M{"d": bson.M{"$gt": tm}}, false},
+		{"in", []string{"In(s, [1,2,3])"}, nil, bson.M{"s": bson.M{"$in": []interface{}{1, 2, 3}}}, false},
+		{"in", []string{"In(s, 1)"}, nil, bson.M{"s": bson.M{"$in": []interface{}{1}}}, false},
+		{"text search or id", []string{"id"}, nil, nil, true},
+		{"struct env", []string{"db_item.id == env_item.id"}, map[string]interface{}{"env_item": &testEnvStruct{ID: "id1"}}, bson.M{"db_item.id": "id1"}, false},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-			gotB, err := ConvertToMongo(ctx, tt.eval, tt.env, nil)
+
+			config := &MongoExprConfig{Env: tt.env}
+			gotB, err := ConvertToMongo(ctx, config, tt.eval...)
 			if tt.wantErr {
 				require.Error(t, err)
 				return
@@ -102,8 +106,10 @@ func BenchmarkConvertToMongo(b *testing.B) {
 	exp := InStringArray("id", ids)
 	//fmt.Println(len(exp))
 
+	config := &MongoExprConfig{Ops: []expr.Option{expr.Patch(&testVisitor{})}}
+
 	for i := 0; i < b.N; i++ {
-		_, _ = ConvertToMongo(ctx, exp, nil, nil, expr.Patch(&testVisitor{}))
+		_, _ = ConvertToMongo(ctx, config, exp)
 	}
 }