From 13c18e116a7b5a1b79271e2c982b81525dcbc10d Mon Sep 17 00:00:00 2001 From: Maksim Syomochkin Date: Thu, 12 Dec 2024 15:55:37 +0300 Subject: [PATCH] inital commit --- .gitignore | 1 + .golangci.yml | 64 ++++++++++++++ Makefile | 23 +++++ aggregate.js | 40 +++++++++ command.js | 53 +++++++++++ delete.go | 24 +++++ deployments/docker-compose.yml | 41 +++++++++ deployments/otel-collector-config.yaml | 19 ++++ find.go | 110 +++++++++++++++++++++++ go.mod | 40 +++++++++ go.sum | 117 +++++++++++++++++++++++++ helpers.go | 12 +++ insert.go | 58 ++++++++++++ main.go | 93 ++++++++++++++++++++ model.go | 33 +++++++ observability.go | 55 ++++++++++++ update.go | 75 ++++++++++++++++ 17 files changed, 858 insertions(+) create mode 100644 .gitignore create mode 100644 .golangci.yml create mode 100644 Makefile create mode 100644 aggregate.js create mode 100644 command.js create mode 100644 delete.go create mode 100644 deployments/docker-compose.yml create mode 100644 deployments/otel-collector-config.yaml create mode 100644 find.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 helpers.go create mode 100644 insert.go create mode 100644 main.go create mode 100644 model.go create mode 100644 observability.go create mode 100644 update.go 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("=============================") +}