commit 13c18e116a7b5a1b79271e2c982b81525dcbc10d Author: Maksim Syomochkin Date: Thu Dec 12 15:55:37 2024 +0300 inital commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..10ff78b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +mongo_crud diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..d7ecabe --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,64 @@ +linters-settings: + govet: + check-shadowing: true + gocyclo: + min-complexity: 20 + maligned: + suggest-new: true + dupl: + threshold: 200 + goconst: + min-len: 2 + min-occurrences: 2 + misspell: + locale: US + lll: + line-length: 140 + goimports: + local-prefixes: github.com/golangci/golangci-lint + gocritic: + enabled-tags: + - performance + - style + - experimental + disabled-checks: + - wrapperFunc + +linters: + disable-all: true + enable: + - govet + - gocyclo + - dupl + - lll + - gosec + - dupl + - goconst + # - depguard + - misspell + - goimports + # - gocritic + - staticcheck + - deadcode + - errcheck + - unused + - gosimple + - structcheck + - varcheck + - ineffassign + - typecheck + - bodyclose + - unconvert + - unparam + - prealloc + - whitespace + - exportloopref + +run: + tests: false + go: "1.21" + skip-dirs: + - swagger-ui + - configs + - templates + - \.go diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a9538f8 --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +start: + docker compose -p mongo -f deployments/docker-compose.yml up -d + +stop: + docker compose -p mongo down + +clean: + rm -f ./mongo_crud + +build: clean + go build . + +run: build + ./mongo_crud + +mongosh: + mongosh "mongodb://root:example@127.0.0.1:27017/?authSource=admin" + +aggregate: + mongosh "mongodb://root:example@127.0.0.1:27017/?authSource=admin" --file aggregate.js + +import: + mongoimport --db=strava --collection=workout "mongodb://root:example@127.0.0.1:27017/?authSource=admin" backup.json \ No newline at end of file diff --git a/aggregate.js b/aggregate.js new file mode 100644 index 0000000..73d7146 --- /dev/null +++ b/aggregate.js @@ -0,0 +1,40 @@ +db = connect( 'mongodb://root:example@127.0.0.1:27017/strava?authSource=admin' ); + +let result = db.workout.aggregate([{ + $match: { + type: 'Run' + } +}, { + $set: { + date: { + $dateFromString: { + dateString: '$start_date' + } + } + } +}, { + $group: { + _id: { + $dateToString: { + format: '%Y-%m', + date: '$date' + } + }, + totalMonthDistance: { + $sum: { + $divide: [ + '$distance', + 1000 + ] + } + } + } +}, { + $match: { + totalMonthDistance: { + $gte: 150 + } + } +}]); + +console.log(result); \ No newline at end of file diff --git a/command.js b/command.js new file mode 100644 index 0000000..5f5c78a --- /dev/null +++ b/command.js @@ -0,0 +1,53 @@ +db.books.insertOne({ + title: 'gRPC: запуск и эксплуатация облачных приложений. Go и Java для Docker и Kubernetes', + author: 'Касун Индрасири', + year: 2020 +}) + +db.books.insertMany([ + { title: 'Go: идиомы и паттерны проектирования', author: 'Боднер Джон', year: 2022 }, + { + title: 'Высоконагруженные приложения. Программирование, масштабирование, поддержка', + author: 'Клеппман Мартин', + year: 2021 + } +]) + +// Найти все документы +db.books.find() +// Найти документы по совпадению конкретного поля +db.books.find({ year: 2021 }) +// Найти документы по условию на кокретное поле +db.books.find({ year: { $gte: 2021 } }) +// Найти документы по условию на кокретное поле и вернуть первый +db.books.findOne({ year: { $gte: 2021 } }) +// Найти документа по одному ИЛИ по второму условию. +db.books.find({ $or: [{ year: { $gte: 2021 } }, { author: 'Касун Индрасири' }] }) + +db.books.findOne({ year: { $gte: 2021 } }, { title: 1, _id: 0 }) +db.books.findOne({ year: { $gte: 2021 } }, { title: 0, _id: 0 }) + +db.books.updateOne( + { + title: 'Высоконагруженные приложения. Программирование, масштабирование, поддержка' + }, + { $set: { rating: 5 } } +) + +db.books.updateMany({ rating: null }, { $set: { rating: 3 } }) + +db.books.replaceOne( + { author: 'Ньюмен Сэм' }, + { + title: 'Создание микросервисов', + author: 'Ньюмен Сэм', + year: 2016, + rating: 3 + }, + { upsert: true } +) + +db.books.countDocuments() + +db.books.deleteOne({ author: 'Ньюмен Сэм' }) +db.books.deleteMany({ rating: { $lt: 5 } }) diff --git a/delete.go b/delete.go new file mode 100644 index 0000000..c737406 --- /dev/null +++ b/delete.go @@ -0,0 +1,24 @@ +package main + +import ( + "context" + "fmt" + "log" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +func deleteAllRows(ctx context.Context, coll *mongo.Collection) { + ctx, span := FollowSpan(ctx, "deleteAllRows") + defer span.End() + + result, err := coll.DeleteMany(ctx, bson.D{}) + if err != nil { + log.Fatal(result) + } + + fmt.Println("Remove all documents...") + fmt.Printf("%d documents removed\n", result.DeletedCount) + fmt.Println("=============================") +} diff --git a/deployments/docker-compose.yml b/deployments/docker-compose.yml new file mode 100644 index 0000000..a421744 --- /dev/null +++ b/deployments/docker-compose.yml @@ -0,0 +1,41 @@ +version: "3.9" +services: + mongo: + image: "mongo" + restart: always + ports: + - 27017:27017 + environment: + MONGO_INITDB_ROOT_USERNAME: root + MONGO_INITDB_ROOT_PASSWORD: example + + mongo-express: + image: mongo-express + restart: always + ports: + - 8081:8081 + environment: + ME_CONFIG_MONGODB_ADMINUSERNAME: root + ME_CONFIG_MONGODB_ADMINPASSWORD: example + ME_CONFIG_MONGODB_URL: mongodb://root:example@mongo:27017/ + + otel-collector: + image: otel/opentelemetry-collector:latest + container_name: otel-collector + command: ["--config=/etc/otel-collector-config.yaml"] + volumes: + - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml + ports: + - "4317:4317" + depends_on: + - jaeger + + jaeger: + image: jaegertracing/all-in-one:latest + container_name: jaeger + environment: + - COLLECTOR_OTLP_ENABLED=true + - COLLECTOR_OTLP_GRPC_HOST-PORT=:4317 + - COLLECTOR_OTLP_GRPC_HOST_PORT=:4317 + ports: + - "16686:16686" \ No newline at end of file diff --git a/deployments/otel-collector-config.yaml b/deployments/otel-collector-config.yaml new file mode 100644 index 0000000..d0410d3 --- /dev/null +++ b/deployments/otel-collector-config.yaml @@ -0,0 +1,19 @@ +receivers: + otlp: + protocols: + grpc: + endpoint: 0.0.0.0:4317 +processors: +exporters: + otlp: + endpoint: "http://jaeger:4317" + tls: + insecure: true + debug: + verbosity: detailed +service: + pipelines: + traces: + receivers: [otlp] + processors: [] + exporters: [otlp, debug] diff --git a/find.go b/find.go new file mode 100644 index 0000000..90332c5 --- /dev/null +++ b/find.go @@ -0,0 +1,110 @@ +package main + +import ( + "context" + "fmt" + "log" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func checkFindErr(err error) { + if err != nil { + if err == mongo.ErrNoDocuments { + return + } + log.Fatal(err) + } +} + +func findAll(ctx context.Context, col *mongo.Collection) { + ctx, span := FollowSpan(ctx, "findAll") + defer span.End() + + fmt.Println("replaceOne document...") + cursor, err := col.Find(ctx, bson.M{}) + checkFindErr(err) + + var books []Book + err = cursor.All(ctx, &books) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Finded %d docs:\n%v\n", len(books), books) + fmt.Println("=============================") +} + +func find(ctx context.Context, col *mongo.Collection) { + ctx, span := FollowSpan(ctx, "find") + defer span.End() + + opts := options.Find().SetSort(bson.M{"rating": 1}) + + cursor, err := col.Find(ctx, bson.M{"year": 2022}, opts) + checkFindErr(err) + + var books []Book + err = cursor.All(ctx, &books) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Search documents where year equal 2022...") + fmt.Printf("Finded %d docs:\n%v\n", len(books), books) + fmt.Println("=============================") +} + +func findWithCondition(ctx context.Context, col *mongo.Collection) { + ctx, span := FollowSpan(ctx, "findWithCondition") + defer span.End() + + filter := bson.M{"year": bson.M{"$gt": 2020}} + + cursor, err := col.Find(ctx, filter) + checkFindErr(err) + + var books []Book + err = cursor.All(ctx, &books) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Search documents where year greather then 2020...") + fmt.Printf("Finded %d docs:\n%v\n", len(books), books) + fmt.Println("=============================") +} + +func findWithOrCondition(ctx context.Context, col *mongo.Collection) { + ctx, span := FollowSpan(ctx, "findWithOrCondition") + defer span.End() + + filter := bson.M{ + "$or": bson.A{ + bson.M{ + "year": bson.M{"$gte": 2020}, + }, + bson.M{ + "author": "Касун Индрасири", + }, + }, + } + + findOptions := options.Find() + findOptions.SetProjection(bson.M{"author": 0}) + + cursor, err := col.Find(ctx, filter, findOptions) + checkFindErr(err) + + var books []Book + err = cursor.All(ctx, &books) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Search documents where year greather then 2020 AND author is 'Касун Индрасири'...") + fmt.Printf("Finded %d docs:\n%v\n", len(books), books) + fmt.Println("=============================") +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..0790573 --- /dev/null +++ b/go.mod @@ -0,0 +1,40 @@ +module github.com/maksim77/mongo_crud + +go 1.21 + +require ( + go.mongodb.org/mongo-driver v1.13.0 + go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.46.0 + go.opentelemetry.io/otel v1.20.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 + go.opentelemetry.io/otel/sdk v1.20.0 + go.opentelemetry.io/otel/trace v1.20.0 + google.golang.org/grpc v1.59.0 +) + +require ( + github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/go-logr/logr v1.3.0 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/golang/protobuf v1.5.3 // indirect + github.com/golang/snappy v0.0.4 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 // indirect + github.com/klauspost/compress v1.17.2 // indirect + github.com/montanaflynn/stats v0.7.1 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect + go.opentelemetry.io/otel/metric v1.20.0 // indirect + go.opentelemetry.io/proto/otlp v1.0.0 // indirect + golang.org/x/crypto v0.15.0 // indirect + golang.org/x/net v0.18.0 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.14.0 // indirect + golang.org/x/text v0.14.0 // indirect + google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect + google.golang.org/protobuf v1.31.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..c2625ca --- /dev/null +++ b/go.sum @@ -0,0 +1,117 @@ +github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= +github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +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/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= +github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 h1:6UKoz5ujsI55KNpsJH3UwCq3T8kKbZwNZBNPuTTje8U= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y= +github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= +github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= +github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= +github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +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/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= +github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk= +github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.mongodb.org/mongo-driver v1.13.0 h1:67DgFFjYOCMWdtTEmKFpV3ffWlFnh+CYZ8ZS/tXWUfY= +go.mongodb.org/mongo-driver v1.13.0/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ= +go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.46.0 h1:1b/GR0eOpqQJ0kjJeuzDwqUzcQD3cnZgsAPlG8032BQ= +go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo v0.46.0/go.mod h1:2nM/khnHtYdbPG/3dWxS8RN+t8/OChavUx5JZHdgAEM= +go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc= +go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 h1:DeFD0VgTZ+Cj6hxravYYZE2W4GlneVH81iAOPjZkzk8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0/go.mod h1:GijYcYmNpX1KazD5JmWGsi4P7dDTTTnfv1UbGn84MnU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 h1:gvmNvqrPYovvyRmCSygkUDyL8lC5Tl845MLEwqpxhEU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0/go.mod h1:vNUq47TGFioo+ffTSnKNdob241vePmtNZnAODKapKd0= +go.opentelemetry.io/otel/metric v1.20.0 h1:ZlrO8Hu9+GAhnepmRGhSU7/VkpjrNowxRN9GyKR4wzA= +go.opentelemetry.io/otel/metric v1.20.0/go.mod h1:90DRw3nfK4D7Sm/75yQ00gTJxtkBxX+wu6YaNymbpVM= +go.opentelemetry.io/otel/sdk v1.20.0 h1:5Jf6imeFZlZtKv9Qbo6qt2ZkmWtdWx/wzcCbNUlAWGM= +go.opentelemetry.io/otel/sdk v1.20.0/go.mod h1:rmkSx1cZCm/tn16iWDn1GQbLtsW/LvsdEEFzCSRM6V0= +go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ= +go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU= +go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= +go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA= +golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.18.0 h1:mIYleuAkSbHh0tCv7RvjL3F6ZVbLjq4+R7zbOn3Kokg= +golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +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-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= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= +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.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= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ= +google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY= +google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo= +google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14= +google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA= +google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= +google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +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/helpers.go b/helpers.go new file mode 100644 index 0000000..c4e5de1 --- /dev/null +++ b/helpers.go @@ -0,0 +1,12 @@ +package main + +import ( + "context" + + "go.opentelemetry.io/otel/trace" +) + +func FollowSpan(ctx context.Context, name string) (_ context.Context, span trace.Span) { + ctx, span = tracer.Start(ctx, name) + return ctx, span +} diff --git a/insert.go b/insert.go new file mode 100644 index 0000000..7b36323 --- /dev/null +++ b/insert.go @@ -0,0 +1,58 @@ +package main + +import ( + "context" + "encoding/binary" + "fmt" + "log" + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" +) + +func insertOne(ctx context.Context, col *mongo.Collection) { + ctx, span := FollowSpan(ctx, "insertOne") + defer span.End() + + fmt.Println("Inserting 1 documents...") + result, err := col.InsertOne(ctx, book) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("One document inserted with id: %s\n", result.InsertedID) + fmt.Println("=============================") +} + +func insertMany(ctx context.Context, col *mongo.Collection) { + ctx, span := FollowSpan(ctx, "insertMany") + defer span.End() + + fmt.Println("Inserting 2 documents...") + inserts := make([]interface{}, 0, len(books)) + for _, book := range books { + inserts = append(inserts, book) + } + + result, err := col.InsertMany(ctx, inserts) + if err != nil { + log.Fatal(err) + } + fmt.Printf("%d documents inserted with ids: %v\n", len(result.InsertedIDs), result.InsertedIDs) + + // ObjectID описание + for _, v := range result.InsertedIDs { + id := [12]byte(v.(primitive.ObjectID)) + byteTime := id[0:4] + byteRandomID := id[4:9] + byteInc := id[9:12] + fmt.Printf("Timestamp: %d\n", binary.BigEndian.Uint32(byteTime)) + fmt.Printf("Timestamp to date: %v\n", time.Unix(int64(binary.BigEndian.Uint32(byteTime)), 0)) + fmt.Printf("Random val per process and machine: %d\n", binary.BigEndian.Uint32(byteRandomID)) + fmt.Printf("Inc counter: %d\n", binary.BigEndian.Uint16(byteInc)) + fmt.Println("*******") + } + + fmt.Println("=============================") +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..2bbe177 --- /dev/null +++ b/main.go @@ -0,0 +1,93 @@ +package main + +import ( + "context" + "log" + "time" + + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "go.opentelemetry.io/contrib/instrumentation/go.mongodb.org/mongo-driver/mongo/otelmongo" + "go.opentelemetry.io/otel" +) + +var tracer = otel.Tracer("mongo_example") + +const URI = "mongodb://127.0.0.1:27017" + +func getClient(ctx context.Context) (*mongo.Client, error) { + ctx, span := FollowSpan(ctx, "getClient") + defer span.End() + + opts := options.Client() + opts.ApplyURI(URI) + optsAuth := options.Credential{ + Username: "root", + Password: "example", + AuthSource: "admin", + } + + opts.SetAuth(optsAuth) + + opts.Monitor = otelmongo.NewMonitor() + + client, err := mongo.Connect(ctx, opts) + if err != nil { + return nil, err + } + return client, nil +} + +func main() { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) + defer cancel() + + shutdown, err := InstallExportPipeline() + if err != nil { + log.Fatal(err.Error()) + } + defer func() { + if err := shutdown(context.Background()); err != nil { + log.Fatal(err.Error()) + } + }() + + // ========= + // ==START== + // ========= + ctx, span := tracer.Start(ctx, "main") + defer span.End() + + // Создаём клиента + client, err := getClient(ctx) + if err != nil { + log.Println(err) + return + } + + defer func() { + if mongoDisconectErr := client.Disconnect(ctx); mongoDisconectErr != nil { + log.Println(mongoDisconectErr) + } + }() + + // Все примеры будут для одной колллекции поэтому сразу создаём соответствующий объект + col := client.Database("teta").Collection("books") + + // Чтобы точно начать с чистого листа удалим коллекцию вообще. + err = col.Drop(ctx) + if err != nil { + log.Fatal(err) + } + + insertOne(ctx, col) + insertMany(ctx, col) + findAll(ctx, col) + find(ctx, col) + findWithCondition(ctx, col) + findWithOrCondition(ctx, col) + updateOne(ctx, col) + updateMany(ctx, col) + replaceOne(ctx, col) + deleteAllRows(ctx, col) +} diff --git a/model.go b/model.go new file mode 100644 index 0000000..9de2034 --- /dev/null +++ b/model.go @@ -0,0 +1,33 @@ +package main + +import "fmt" + +type Book struct { + Title string `bson:"title"` + Author string `bson:"author"` + Year int `bson:"year"` + Rating int `bson:"rating"` +} + +func (b Book) String() string { + return fmt.Sprintf("{\n\tTtile: %s,\n\tAuthor: %s\n\tYear: %d\n\tRating: %d\n}\n", b.Title, b.Author, b.Year, b.Rating) +} + +var book Book = Book{ + Title: "gRPC: запуск и эксплуатация облачных приложений. Go и Java для Docker и Kubernetes", + Author: "Касун Индрасири", + Year: 2020, +} + +var books []Book = []Book{ + { + Title: "Go: идиомы и паттерны проектирования", + Author: "Боднер Джон", + Year: 2022, + }, + { + Title: "Высоконагруженные приложения. Программирование, масштабирование, поддержка", + Author: "Клеппман Мартин", + Year: 2021, + }, +} diff --git a/observability.go b/observability.go new file mode 100644 index 0000000..e9428c3 --- /dev/null +++ b/observability.go @@ -0,0 +1,55 @@ +package main + +import ( + "context" + "fmt" + "log" + "time" + + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc" + "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/sdk/resource" + sdktrace "go.opentelemetry.io/otel/sdk/trace" + semconv "go.opentelemetry.io/otel/semconv/v1.4.0" +) + +func InstallExportPipeline() (func(context.Context) error, error) { + traceClient := otlptracegrpc.NewClient( + otlptracegrpc.WithInsecure(), + otlptracegrpc.WithEndpoint("127.0.0.1:4317"), + ) + sctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + + traceExp, err := otlptrace.New(sctx, traceClient) + if err != nil { + log.Fatal(err) + } + if err != nil { + return nil, fmt.Errorf("creating stdout exporter: %w", err) + } + + res, err := resource.New(context.Background(), + resource.WithFromEnv(), + resource.WithProcess(), + resource.WithTelemetrySDK(), + resource.WithHost(), + resource.WithAttributes( + semconv.ServiceNameKey.String("go_test"), + ), + ) + if err != nil { + log.Fatal(err) + } + + tracerProvider := sdktrace.NewTracerProvider( + sdktrace.WithBatcher(traceExp), + sdktrace.WithResource(res), + ) + otel.SetTracerProvider(tracerProvider) + otel.SetTextMapPropagator(propagation.TraceContext{}) + + return tracerProvider.Shutdown, nil +} diff --git a/update.go b/update.go new file mode 100644 index 0000000..5ad9ef5 --- /dev/null +++ b/update.go @@ -0,0 +1,75 @@ +package main + +import ( + "context" + "fmt" + "log" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +func updateOne(ctx context.Context, col *mongo.Collection) { + ctx, span := FollowSpan(ctx, "updateOne") + defer span.End() + + filter := bson.M{ + "title": "Высоконагруженные приложения. Программирование, масштабирование, поддержка", + } + + update := bson.M{ + "$set": bson.M{"rating": 5}, + } + + result, err := col.UpdateOne(ctx, filter, update) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Updating 1 documents...") + fmt.Printf("Matched docs: %d. Updated docs: %d\n", result.MatchedCount, result.ModifiedCount) + fmt.Println("=============================") +} + +func updateMany(ctx context.Context, col *mongo.Collection) { + ctx, span := FollowSpan(ctx, "updateMany") + defer span.End() + + filter := bson.M{ + "rating": 0, + } + + update := bson.M{ + "$set": bson.M{"rating": 3}, + } + + result, err := col.UpdateMany(ctx, filter, update) + if err != nil { + log.Fatal(err) + } + + fmt.Println("Updating many documents...") + fmt.Printf("Matched docs: %d. Updated docs: %d\n", result.MatchedCount, result.ModifiedCount) + fmt.Println("=============================") +} + +func replaceOne(ctx context.Context, col *mongo.Collection) { + ctx, span := FollowSpan(ctx, "replaceOne") + defer span.End() + + fmt.Println("replaceOne document...") + var updatedBook Book = Book{ + Author: "Ньюмен Сэм", + Title: "Создание микросервисов", + Year: 2016, + } + + result, err := col.ReplaceOne(ctx, bson.M{"author": "Ньюмен Сэм"}, updatedBook, options.Replace().SetUpsert(true)) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Matched docs: %d. Updated docs: %d. Upserted docs: %d\n", result.MatchedCount, result.ModifiedCount, result.UpsertedCount) + fmt.Println("=============================") +}