diff --git a/go.mod b/go.mod
index 8cd52d3b3533422183a392bd755566f2090087d5..c1c371718e1900db44be42b040fd4d19424ce424 100644
--- a/go.mod
+++ b/go.mod
@@ -3,9 +3,9 @@ module git.perx.ru/perxis/perxis-go
 go 1.21
 
 require (
-	github.com/antonmedv/expr v1.9.0
 	github.com/avast/retry-go/v4 v4.5.1
 	github.com/bep/gowebp v0.2.0
+	github.com/expr-lang/expr v1.15.8
 	github.com/go-kit/kit v0.13.0
 	github.com/gosimple/slug v1.13.1
 	github.com/hashicorp/go-multierror v1.1.1
diff --git a/go.sum b/go.sum
index fcb538d7446ef905cc38573b2c88d2496b342ac9..4fa995ca097f0a961d0c4fc9d10cbe640e972c00 100644
--- a/go.sum
+++ b/go.sum
@@ -2,9 +2,6 @@ cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiV
 cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
 cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
 cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
-github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
-github.com/antonmedv/expr v1.9.0 h1:j4HI3NHEdgDnN9p6oI6Ndr0G5QryMY0FNxT4ONrFDGU=
-github.com/antonmedv/expr v1.9.0/go.mod h1:5qsM3oLGDND7sDmQGDXHkYfkjYMUX14qsgqmHhwGEk8=
 github.com/avast/retry-go/v4 v4.5.1 h1:AxIx0HGi4VZ3I02jr78j5lZ3M6x1E0Ivxa6b0pUUh7o=
 github.com/avast/retry-go/v4 v4.5.1/go.mod h1:/sipNsvNB3RRuT5iNcb6h73nw3IBmXJ/H3XrCQYSOpc=
 github.com/bep/gowebp v0.2.0 h1:ZVfK8i9PpZqKHEmthQSt3qCnnHycbLzBPEsVtk2ch2Q=
@@ -12,12 +9,11 @@ github.com/bep/gowebp v0.2.0/go.mod h1:ZhFodwdiFp8ehGJpF4LdPl6unxZm9lLFjxD3z2h2A
 github.com/brianvoe/gofakeit/v6 v6.26.3 h1:3ljYrjPwsUNAUFdUIr2jVg5EhKdcke/ZLop7uVg1Er8=
 github.com/brianvoe/gofakeit/v6 v6.26.3/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
-github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
+github.com/expr-lang/expr v1.15.8 h1:FL8+d3rSSP4tmK9o+vKfSMqqpGL8n15pEPiHcnBpxoI=
+github.com/expr-lang/expr v1.15.8/go.mod h1:uCkhfG+x7fcZ5A5sXHKuQ07jGZRl6J0FCAaf2k4PtVQ=
 github.com/go-kit/kit v0.13.0 h1:OoneCcHKHQ03LfBpoQCUfCluwd2Vt3ohz+kvbJneZAU=
 github.com/go-kit/kit v0.13.0/go.mod h1:phqEHMMUbyrCFCTgH48JueqrM3md2HcAZ8N3XE4FKDg=
 github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU=
@@ -64,10 +60,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
-github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
-github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
-github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -87,25 +79,19 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS
 github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rivo/tview v0.0.0-20200219210816-cd38d7432498/go.mod h1:6lkG1x+13OShEf0EaOCaTQYyB7d5nSbb181KtjlS+84=
-github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
 github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
 github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
 github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc=
 github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
-github.com/sanity-io/litter v1.2.0/go.mod h1:JF6pZUFgu2Q0sBZ+HSV35P8TVPI1TTzEwyu9FXAw2W4=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
 github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/objx v0.5.1 h1:4VhoImhV/Bm0ToFkXFi8hXNXwpDRZ/ynw3amt82mzq0=
 github.com/stretchr/objx v0.5.1/go.mod h1:/iHQpkQwBD6DLUmQ4pE+s1TXdob1mORJ4/UFdrifcy0=
-github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
 github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
@@ -160,8 +146,6 @@ golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
 golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -172,7 +156,6 @@ golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
@@ -198,7 +181,6 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/pkg/environments/environment.go b/pkg/environments/environment.go
index cbd468dc361951e048a0840f4158a42c962e7af1..e9d2b96e8337ac2ad94315b671aeea42e54c47cb 100644
--- a/pkg/environments/environment.go
+++ b/pkg/environments/environment.go
@@ -91,24 +91,4 @@ func (e Environment) Clone() *Environment {
 	}
 
 	return clone
-}
-
-func (e Environment) Fetch(i interface{}) interface{} {
-	p, _ := i.(string)
-	switch p {
-	case "ID":
-		return e.ID
-	case "SpaceID":
-		return e.SpaceID
-	case "Description":
-		return e.Description
-	case "StateInfo":
-		return e.StateInfo
-	case "Aliases":
-		return e.Aliases
-	case "Config":
-		return e.Config
-	default:
-		panic("unknown parameter")
-	}
-}
+}
\ No newline at end of file
diff --git a/pkg/expr/config.go b/pkg/expr/config.go
index 628111173d92f81ccdcc5e4c40b1aecc2ff27626..e6ba9d90b4f4e04c56c17b8591d4a92e30984e6c 100644
--- a/pkg/expr/config.go
+++ b/pkg/expr/config.go
@@ -1,8 +1,8 @@
 package expr
 
 import (
-	"github.com/antonmedv/expr"
-	"github.com/antonmedv/expr/conf"
+	"github.com/expr-lang/expr"
+	"github.com/expr-lang/expr/conf"
 )
 
 type ExprConfig struct {
diff --git a/pkg/expr/expr.go b/pkg/expr/expr.go
index 93d6ee612968ac0a7e1c963a05cda4955532f110..1969b58c6bec892b05f8eff38eec86f3d4099e01 100644
--- a/pkg/expr/expr.go
+++ b/pkg/expr/expr.go
@@ -5,9 +5,9 @@ import (
 	"strings"
 
 	"git.perx.ru/perxis/perxis-go/pkg/data"
-	compiler2 "github.com/antonmedv/expr/compiler"
-	"github.com/antonmedv/expr/parser"
-	"github.com/antonmedv/expr/vm"
+	exprcompiler "github.com/expr-lang/expr/compiler"
+	"github.com/expr-lang/expr/parser"
+	"github.com/expr-lang/expr/vm"
 	"golang.org/x/net/context"
 )
 
@@ -39,7 +39,7 @@ func Eval(ctx context.Context, input string, env map[string]interface{}) (interf
 
 	env, _ = cfg.Env.(map[string]interface{})
 
-	program, err := compiler2.Compile(tree, nil)
+	program, err := exprcompiler.Compile(tree, cfg)
 	if err != nil {
 		return nil, err
 	}
@@ -78,4 +78,4 @@ func IsExpression(input string) bool {
 	}
 
 	return false
-}
+}
\ No newline at end of file
diff --git a/pkg/expr/expr_test.go b/pkg/expr/expr_test.go
index 5eafc368bed934e0bd0805f4818442a75256931c..35153da271daace9f9acb6c7a02411f948f47054 100644
--- a/pkg/expr/expr_test.go
+++ b/pkg/expr/expr_test.go
@@ -1,11 +1,13 @@
 package expr
 
 import (
+	"context"
 	"fmt"
 	"testing"
 	"time"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 func TestIsExpression(t *testing.T) {
@@ -49,3 +51,75 @@ func TestIsExpression(t *testing.T) {
 		})
 	}
 }
+
+type testEnvStruct struct {
+	ID   string      `expr:"id"`
+	Size int         `expr:"size"`
+	Data interface{} `expr:"data"`
+}
+
+func (s *testEnvStruct) Equal(other *testEnvStruct) bool {
+	return s.ID == other.ID
+}
+
+func TestExpr_Example(t *testing.T) {
+	ctx := context.Background()
+
+	tests := []struct {
+		name       string
+		exp        string
+		env        map[string]interface{}
+		wantErr    bool
+		wantResult interface{}
+	}{
+		{
+			name:       "get field by expr tag",
+			exp:        "s.id",
+			env:        map[string]interface{}{"s": &testEnvStruct{ID: "id1"}},
+			wantResult: "id1",
+		},
+		{
+			name:       "get field by field name",
+			exp:        "s.ID",
+			env:        map[string]interface{}{"s": &testEnvStruct{ID: "id1"}},
+			wantResult: "id1",
+		},
+		{
+			name:       "get nested field",
+			exp:        "m.s.size",
+			env:        map[string]interface{}{"m": map[string]interface{}{"s": &testEnvStruct{Size: 1}}},
+			wantResult: 1,
+		},
+		{
+			name:       "check field",
+			exp:        "s.data.size < 100",
+			env:        map[string]interface{}{"s": &testEnvStruct{Data: &testEnvStruct{Size: 0}}},
+			wantResult: true,
+		},
+		{
+			name:       "use method",
+			exp:        "s1.Equal(s2)",
+			env:        map[string]interface{}{"s1": &testEnvStruct{ID: "id1"}, "s2": &testEnvStruct{ID: "id2"}},
+			wantResult: false,
+		},
+		{
+			name:    "field not exists",
+			exp:     "s.not_exists",
+			env:     map[string]interface{}{"s": &testEnvStruct{}},
+			wantErr: true,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			result, err := Eval(ctx, tt.exp, tt.env)
+			if tt.wantErr {
+				require.Error(t, err)
+				return
+			}
+
+			require.NoError(t, err)
+			require.Equal(t, tt.wantResult, result)
+		})
+	}
+}
diff --git a/pkg/expr/mongo.go b/pkg/expr/mongo.go
index 989454178f640144791a9e6fd84d39317fd1e283..397043c2fc9e99ad26498b3aecbf87280ac795a1 100644
--- a/pkg/expr/mongo.go
+++ b/pkg/expr/mongo.go
@@ -6,11 +6,11 @@ import (
 	"regexp"
 	"strings"
 
-	"github.com/antonmedv/expr"
-	"github.com/antonmedv/expr/ast"
-	compiler2 "github.com/antonmedv/expr/compiler"
-	"github.com/antonmedv/expr/conf"
-	"github.com/antonmedv/expr/parser"
+	"github.com/expr-lang/expr"
+	"github.com/expr-lang/expr/ast"
+	exprcompiler "github.com/expr-lang/expr/compiler"
+	"github.com/expr-lang/expr/conf"
+	"github.com/expr-lang/expr/parser"
 	"go.mongodb.org/mongo-driver/bson"
 )
 
@@ -76,7 +76,7 @@ func (c *compiler) eval(node ast.Node) interface{} {
 		Node:   node,
 		Source: c.tree.Source,
 	}
-	prg, err := compiler2.Compile(t, c.config)
+	prg, err := exprcompiler.Compile(t, c.config)
 	if err != nil {
 		panic(fmt.Sprintf("compile error %s", err.Error()))
 	}
@@ -107,18 +107,14 @@ func (c *compiler) compile(node ast.Node) interface{} {
 		return c.UnaryNode(n)
 	case *ast.BinaryNode:
 		return c.BinaryNode(n)
-	case *ast.MatchesNode:
-		return c.MatchesNode(n)
-	case *ast.PropertyNode:
-		return c.PropertyNode(n)
-	case *ast.IndexNode:
-		return c.IndexNode(n)
+	case *ast.MemberNode:
+		return c.MemberNode(n)
+	case *ast.ChainNode:
+		return c.ChainNode(n)
 	case *ast.SliceNode:
 		return c.SliceNode(n)
-	case *ast.MethodNode:
-		return c.MethodNode(n)
-	case *ast.FunctionNode:
-		return c.FunctionNode(n)
+	case *ast.CallNode:
+		return c.CallNode(n)
 	case *ast.BuiltinNode:
 		return c.BuiltinNode(n)
 	case *ast.ClosureNode:
@@ -127,6 +123,8 @@ func (c *compiler) compile(node ast.Node) interface{} {
 		return c.PointerNode(n)
 	case *ast.ConditionalNode:
 		return c.ConditionalNode(n)
+	case *ast.VariableDeclaratorNode:
+		return c.VariableDeclaratorNode(n)
 	case *ast.ArrayNode:
 		return c.ArrayNode(n)
 	case *ast.MapNode:
@@ -208,12 +206,14 @@ func (c *compiler) ConstantNode(node *ast.ConstantNode) interface{} {
 }
 
 func (c *compiler) UnaryNode(node *ast.UnaryNode) interface{} {
-	op := c.compile(node.Node)
-
 	switch node.Operator {
-
 	case "!", "not":
-		return bson.M{"$not": op}
+		nodeIn, ok := node.Node.(*ast.BinaryNode)
+		if ok && nodeIn.Operator == "in" {
+			return bson.M{c.identifier(nodeIn.Left): bson.M{"$nin": c.eval(nodeIn.Right)}}
+		}
+
+		return bson.M{"$not": c.compile(node.Node)}
 	default:
 		panic(fmt.Sprintf("unknown operator (%v)", node.Operator))
 	}
@@ -221,8 +221,8 @@ func (c *compiler) UnaryNode(node *ast.UnaryNode) interface{} {
 
 func (c *compiler) identifier(node ast.Node) string {
 	switch l := node.(type) {
-	case *ast.PropertyNode:
-		return c.PropertyNode(l)
+	case *ast.MemberNode:
+		return c.MemberNode(l)
 	case *ast.IdentifierNode:
 		return c.IdentifierNode(l)
 	}
@@ -324,45 +324,24 @@ func (c *compiler) BinaryNode(node *ast.BinaryNode) interface{} {
 	}
 }
 
-func (c *compiler) MatchesNode(node *ast.MatchesNode) interface{} {
-	panic("unsupported match node")
-	//if node.Regexp != nil {
-	//	c.compile(node.Left)
-	//	c.emit(OpMatchesConst, c.makeConstant(node.Regexp)...)
-	//	return
-	//}
-	//c.compile(node.Left)
-	//c.compile(node.Right)
-	//c.emit(OpMatches)
+func (c *compiler) ChainNode(node *ast.ChainNode) string {
+	panic("unsupported chain node")
 }
 
-func (c *compiler) PropertyNode(node *ast.PropertyNode) string {
+func (c *compiler) MemberNode(node *ast.MemberNode) string {
 	v := c.compile(node.Node)
 	if val, ok := v.(string); ok {
-		return fmt.Sprintf("%s.%s", val, node.Property)
+		return fmt.Sprintf("%s.%s", val, c.compile(node.Property))
 	}
 	panic(fmt.Sprintf("unsupported property for %v", ast.Dump(node.Node)))
 }
 
-func (c *compiler) IndexNode(node *ast.IndexNode) string {
-	return fmt.Sprintf("{index-%v}", c.compile(node.Index))
-}
-
 func (c *compiler) SliceNode(node *ast.SliceNode) interface{} {
 	panic("unsupported slice node")
 }
 
-func (c *compiler) MethodNode(node *ast.MethodNode) interface{} {
-	panic("unsupported method node")
-	//c.compile(node.Node)
-	//for _, arg := range node.Arguments {
-	//	c.compile(arg)
-	//}
-	//c.emit(OpMethod, c.makeConstant(Call{Name: node.Method, Size: len(node.Arguments)})...)
-}
-
-func (c *compiler) FunctionNode(node *ast.FunctionNode) interface{} {
-	switch node.Name {
+func (c *compiler) CallNode(node *ast.CallNode) interface{} {
+	switch node.Callee.String() {
 	case "search", "q":
 		val := c.compile(node.Arguments[0])
 		return bson.M{"$text": bson.M{"$search": val}}
@@ -633,6 +612,10 @@ func (c *compiler) ConditionalNode(node *ast.ConditionalNode) interface{} {
 	//c.patchJump(end)
 }
 
+func (c *compiler) VariableDeclaratorNode(node *ast.VariableDeclaratorNode) int {
+	panic("unsupported variable declarator node ")
+}
+
 func (c *compiler) ArrayNode(node *ast.ArrayNode) interface{} {
 	panic("unsupported array node")
 	//for _, node := range node.Nodes {
diff --git a/pkg/expr/mongo_test.go b/pkg/expr/mongo_test.go
index 75ec627c124cc0a24768d3cec30a4eac0ae34c15..dadf30e720ce88cd51591989dd4e0082f3f0883f 100644
--- a/pkg/expr/mongo_test.go
+++ b/pkg/expr/mongo_test.go
@@ -6,8 +6,8 @@ import (
 	"time"
 
 	"git.perx.ru/perxis/perxis-go/pkg/id"
-	"github.com/antonmedv/expr"
-	"github.com/antonmedv/expr/ast"
+	"github.com/expr-lang/expr"
+	"github.com/expr-lang/expr/ast"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 	"go.mongodb.org/mongo-driver/bson"
@@ -29,6 +29,10 @@ func TestConvertToMongo(t *testing.T) {
 	}{
 		{"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},
+		{"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},
@@ -51,6 +55,7 @@ func TestConvertToMongo(t *testing.T) {
 		{"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},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -83,8 +88,7 @@ func BenchmarkConvertToMongo(b *testing.B) {
 
 type testVisitor struct{}
 
-func (v *testVisitor) Enter(node *ast.Node) {}
-func (v *testVisitor) Exit(node *ast.Node) {
+func (v *testVisitor) Visit(node *ast.Node) {
 	if n, ok := (*node).(*ast.IdentifierNode); ok {
 		n.Value = "some" + "." + n.Value
 	}
diff --git a/pkg/expr/time.go b/pkg/expr/time.go
index 740da301a70b65a15f83ac70b1f512c47c171b35..b72292c0c9f4d85bbe42d282f52dcde060cdf8e4 100644
--- a/pkg/expr/time.go
+++ b/pkg/expr/time.go
@@ -3,7 +3,7 @@ package expr
 import (
 	"time"
 
-	"github.com/antonmedv/expr"
+	"github.com/expr-lang/expr"
 )
 
 const DefaultTimeLayout = time.RFC3339
@@ -18,7 +18,6 @@ func init() {
 		expr.Operator("<", "Time.Before"),
 		expr.Operator(">", "Time.After"),
 		expr.Operator("<=", "Time.BeforeOrEqual"),
-		expr.Operator(">", "Time.After"),
 		expr.Operator(">=", "Time.AfterOrEqual"),
 
 		// Time and duration manipulation.
diff --git a/pkg/files/file.go b/pkg/files/file.go
index 0e4d89f7004413b2c2a0ae9eff663cdcfc0ef3a1..d2236b83368e3d5efc763fd6f7e53664e15cc827 100644
--- a/pkg/files/file.go
+++ b/pkg/files/file.go
@@ -16,13 +16,13 @@ const (
 
 // File - описание файла в системе хранения perxis
 type File struct {
-	ID       string  `mapstructure:"id,omitempty" json:"id"`                                       // Уникальный идентификатор файла в хранилище
-	Name     string  `mapstructure:"name,omitempty" json:"name" bson:"name,omitempty"`             // Имя файла
-	Size     int     `mapstructure:"size,omitempty" json:"size" bson:"size,omitempty"`             // Размер файла
-	MimeType string  `mapstructure:"mimeType,omitempty" json:"mimeType" bson:"mimeType,omitempty"` // Mime-type файла
-	URL      string  `mapstructure:"url,omitempty" json:"url" bson:"url,omitempty"`                // Адрес для загрузки файла
-	Key      string  `mapstructure:"key,omitempty" json:"key" bson:"key,omitempty"`                // Ключ для хранения файла в хранилище
-	File     fs.File `mapstructure:"-" json:"-" bson:"-"`                                          // Файл для загрузки(из файловой системы)
+	ID       string  `mapstructure:"id,omitempty" json:"id" expr:"id"`                                              // Уникальный идентификатор файла в хранилище
+	Name     string  `mapstructure:"name,omitempty" json:"name" bson:"name,omitempty" expr:"name"`                  // Имя файла
+	Size     int     `mapstructure:"size,omitempty" json:"size" bson:"size,omitempty" expr:"size"`                  // Размер файла
+	MimeType string  `mapstructure:"mimeType,omitempty" json:"mimeType" bson:"mimeType,omitempty" expr:"mime_type"` // Mime-type файла
+	URL      string  `mapstructure:"url,omitempty" json:"url" bson:"url,omitempty" expr:"url"`                      // Адрес для загрузки файла
+	Key      string  `mapstructure:"key,omitempty" json:"key" bson:"key,omitempty" expr:"key"`                      // Ключ для хранения файла в хранилище
+	File     fs.File `mapstructure:"-" json:"-" bson:"-"`                                                           // Файл для загрузки(из файловой системы)
 }
 
 func (f File) Clone() *File {
@@ -47,26 +47,6 @@ func (f *File) SetURLWithTemplate(t *template.Template) error {
 	return nil
 }
 
-func (f File) Fetch(i interface{}) interface{} {
-	p, _ := i.(string)
-	switch p {
-	case "id":
-		return f.ID
-	case "name":
-		return f.Name
-	case "size":
-		return f.Size
-	case "mime_type":
-		return f.MimeType
-	case "url":
-		return f.URL
-	case "key":
-		return f.Key
-	default:
-		panic("unknown parameter")
-	}
-}
-
 func NewFile(name, mimeType string, size int, temp bool) *File {
 	i := id.GenerateNewID()
 	if temp {
diff --git a/pkg/files/file_test.go b/pkg/files/file_test.go
index 14fb89ce8c054d57ea708a10eb27318b474ff99c..617bed4c09ef95ab58874d856a36c5584abd4589 100644
--- a/pkg/files/file_test.go
+++ b/pkg/files/file_test.go
@@ -1,9 +1,11 @@
 package files
 
 import (
+	"context"
 	"testing"
 	"text/template"
 
+	"git.perx.ru/perxis/perxis-go/pkg/expr"
 	"github.com/stretchr/testify/require"
 )
 
@@ -55,3 +57,35 @@ func TestFile_SetURLWithTemplate(t *testing.T) {
 		})
 	}
 }
+
+func TestFile_InExpr(t *testing.T) {
+	ctx := context.Background()
+
+	tests := []struct {
+		exp        string
+		env        map[string]interface{}
+		wantResult interface{}
+		wantErr    bool
+	}{
+		{"f.id", map[string]interface{}{"f": &File{ID: "some_id"}}, "some_id", false},
+		{"f.name", map[string]interface{}{"f": &File{Name: "some_name"}}, "some_name", false},
+		{"f.size", map[string]interface{}{"f": &File{Size: 1}}, 1, false},
+		{"f.mime_type", map[string]interface{}{"f": &File{MimeType: "some_mime_type"}}, "some_mime_type", false},
+		{"f.url", map[string]interface{}{"f": &File{URL: "some_url"}}, "some_url", false},
+		{"f.key", map[string]interface{}{"f": &File{Key: "some_key"}}, "some_key", false},
+		{"f.not_exists", map[string]interface{}{"f": &File{}}, "", true},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.exp, func(t *testing.T) {
+			result, err := expr.Eval(ctx, tt.exp, tt.env)
+			if tt.wantErr {
+				require.Error(t, err)
+				return
+			}
+
+			require.NoError(t, err)
+			require.Equal(t, tt.wantResult, result)
+		})
+	}
+}
diff --git a/pkg/references/reference.go b/pkg/references/reference.go
index 5740c929bfde2c0c11abcd96d75ce3122448f50e..171ded420c3fd5601cac9ad9f74ad69883f964ea 100644
--- a/pkg/references/reference.go
+++ b/pkg/references/reference.go
@@ -7,9 +7,9 @@ import (
 )
 
 type Reference struct {
-	ID           string `json:"id" bson:"id" mapstructure:"id"`
-	CollectionID string `json:"collection_id" bson:"collection_id" mapstructure:"collection_id"`
-	Disabled     bool   `json:"disabled,omitempty" bson:"disabled,omitempty" mapstructure:"disabled"`
+	ID           string `json:"id" bson:"id" mapstructure:"id" expr:"id"`
+	CollectionID string `json:"collection_id" bson:"collection_id" mapstructure:"collection_id" expr:"collection_id"`
+	Disabled     bool   `json:"disabled,omitempty" bson:"disabled,omitempty" mapstructure:"disabled" expr:"disabled"`
 }
 
 func (r *Reference) MarshalBSON() ([]byte, error) {
@@ -108,17 +108,3 @@ func EqualArrays(sr1, sr2 []*Reference) bool {
 func (r *Reference) IsValid() bool {
 	return r != nil && r.ID != "" && r.CollectionID != "" && !r.Disabled
 }
-
-func (r *Reference) Fetch(i interface{}) interface{} {
-	p, _ := i.(string)
-	switch p {
-	case "id":
-		return r.ID
-	case "collection_id":
-		return r.CollectionID
-	case "disabled":
-		return r.Disabled
-	default:
-		panic("unknown parameter")
-	}
-}
diff --git a/pkg/references/reference_test.go b/pkg/references/reference_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..5e79de47ab96cc9e48b8ba0eb644f9519e9ee914
--- /dev/null
+++ b/pkg/references/reference_test.go
@@ -0,0 +1,41 @@
+package references
+
+import (
+	"context"
+	"testing"
+
+	"git.perx.ru/perxis/perxis-go/pkg/expr"
+	"github.com/stretchr/testify/require"
+)
+
+func TestReference_InExpr(t *testing.T) {
+	ctx := context.Background()
+
+	tests := []struct {
+		exp        string
+		env        map[string]interface{}
+		wantResult interface{}
+		wantErr    bool
+	}{
+		{"r.id", map[string]interface{}{"r": &Reference{ID: "some_id"}}, "some_id", false},
+		{"r.collection_id", map[string]interface{}{"r": &Reference{CollectionID: "some_coll_id"}}, "some_coll_id", false},
+		{"r.disabled", map[string]interface{}{"r": &Reference{Disabled: true}}, true, false},
+		{"r.String()", map[string]interface{}{"r": &Reference{ID: "id", CollectionID: "collID"}}, "collID.id", false},
+		{"r1.Equal(r2)", map[string]interface{}{"r1": &Reference{"id", "collID", false}, "r2": &Reference{"id", "collID", false}}, true, false},
+		{"r.IsValid()", map[string]interface{}{"r": &Reference{}}, false, false},
+		{"r.not_exists", map[string]interface{}{"r": &Reference{}}, false, true},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.exp, func(t *testing.T) {
+			result, err := expr.Eval(ctx, tt.exp, tt.env)
+			if tt.wantErr {
+				require.Error(t, err)
+				return
+			}
+
+			require.NoError(t, err)
+			require.Equal(t, tt.wantResult, result)
+		})
+	}
+}
diff --git a/pkg/spaces/space.go b/pkg/spaces/space.go
index aa039c46f95e6c1ec3b0e49b65e766dc7451cd9f..83edb3f14706793aed6077adcee856598358b044 100644
--- a/pkg/spaces/space.go
+++ b/pkg/spaces/space.go
@@ -42,24 +42,4 @@ type StateInfo struct {
 
 func (s Space) Clone() *Space {
 	return &s
-}
-
-func (s Space) Fetch(i interface{}) interface{} {
-	p, _ := i.(string)
-	switch p {
-	case "ID":
-		return s.ID
-	case "OrgID":
-		return s.OrgID
-	case "Name":
-		return s.Name
-	case "Description":
-		return s.Description
-	case "Config":
-		return s.Config
-	case "StateInfo":
-		return s.StateInfo
-	default:
-		panic("unknown parameter")
-	}
-}
+}
\ No newline at end of file