How to solve "command find requires authentication" using Golang and MongoDriver - mongodb

I need help to fix the error. I'm using IBM mongo services.
go version go1.13.6 darwin/amd64
mongo driver version 1.2.1
The connection is working, I can read and write but sometimes it returns
: command find requires authentication and command insert requires authentication
MONGO_DB_URI=mongodb://username:password:port,host/dbname?authSource=admin&replicaSet=replset&connect=direct&alias=default
Connect:
func ConnectDatabase() *mongo.Client {
clientOptions := options.Client().ApplyURI(os.Getenv("MONGO_DB_URI"))
ctx, _ := context.WithTimeout(context.Background(), 30*time.Second)
var err error
client, err = mongo.Connect(ctx, clientOptions)
if err != nil {
log.Fatal(err)
}
ctx, _ = context.WithTimeout(context.Background(), 10*time.Second)
err = client.Ping(ctx, nil)
if err != nil {
log.Fatal(err)
return nil
}
fmt.Println("Connected to MongoDB!")
return client
}
Read:
func FindAll(collectionName string, query bson.M) (*mongo.Cursor, error) {
collection := client.Database("dbname").Collection(collectionName)
singleResult, err := collection.Find(context.TODO(), query)
return singleResult, err
}
Read:
ctx, _ := context.WithTimeout(context.Background(), 20*time.Second)
cur, err := mongo.GetCollection("collection_name").Find(ctx, createQuery())
if err != nil {
log.Println(err.Error())
}
I'm using the same database and the same configurations at our another Python Project. No exceptions.

There is a difference between connecting to a DB and performing operations on the DB.
Mongo lets you connect without authentication because you have to be able to connect to be able to authenticate.
var cred options.Credential
cred.AuthSource = YourAuthSource
cred.Username = YourUserName
cred.Password = YourPassword
// set client options
clientOptions := options.Client().ApplyURI(os.Getenv("MONGO_DB_URI")).SetAuth(cred)
//... the rest of your code
Hope this helps.

Related

Connect Go to Mongo Atlas and find documents

I'm a newbie to Go and trying to connect my sample application to Mongo Atlas
I`ve create a cluster in Mongo Atlas which has the following information:
I'm trying to retrieve documents from the collection but it fails to find any:
I'm able to connect to the DB, but when I run .Find() then I get an error of document is nil
When i run a specific query (for email) then it works.
When i run a general query (context.TODO()) then it is not working
What am I missing here?
const connectionStr = "mongodb+srv://" + MONGO_USER + ":" + MONGO_PASSWORD + "#cluster0.3ymvqrs.mongodb.net/?retryWrites=true&w=majority"
serverAPIOptions := options.ServerAPI(options.ServerAPIVersion1)
clientOptions := options.Client().
ApplyURI(connectionStr).
SetServerAPIOptions(serverAPIOptions)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
client, err := mongo.Connect(ctx, clientOptions)
if err != nil {
log.Fatal(err, client)
}
// Select the database and collection
database := client.Database("sample_mflix")
commentsCollection := database.Collection("comments")
// Retrieve documents from the collection
// cursor, err := commentsCollection.Find(context.TODO(), nil) // not working
cursor, err := commentsCollection.Find(ctx, bson.M{"email": "roxanne_mckee#gameofthron.es"}) // working
if err != nil {
log.Fatal(err)
}
defer cursor.Close(context.TODO())

How to obtain MongoDB version using Golang library?

I am using Go's MongodDB driver (https://pkg.go.dev/go.mongodb.org/mongo-driver#v1.8.0/mongo#section-documentation) and want to obtain the version of the mongoDB server deployed.
For instance, if it would been a MySQL database, I can do something like below:
db, err := sql.Open("mysql", DbUser+":"+DbPwd+"#tcp("+Host+")/"+DbName)
if err != nil {
log.Printf("Error while connecting to DB: %v", err)
}
defer db.Close()
var dbVersion string
if err := db.QueryRow("SELECT VERSION()").Scan(&dbVersion); err != nil {
dbVersion = "NA"
log.Printf("Couldnt obtain db version: %w", err)
}
fmt.Println("DB Version: ", dbVersion)
I went through the documentation but am not able to find a clue.
I also need to fetch other metadata like Size of a particular database etc.
Any help would be appreciated. Thanks!
The MongoDB version can be acquired by running a command, specifically the buildInfo command.
Using the shell, this is how you could do it:
db.runCommand({buildInfo: 1})
The result is a document whose version property holds the server version, e.g.:
{
"version" : "5.0.6",
...
}
To run commands using the official driver, use the Database.RunCommand() method.
For example:
// Connect to MongoDB and acquire a Database:
ctx := context.Background()
opts := options.Client().ApplyURI("mongodb://localhost")
client, err := mongo.Connect(ctx, opts)
if err != nil {
log.Fatalf("Failed to connect to db: %v", err)
}
defer client.Disconnect(ctx)
db := client.Database("your-db-name")
// And now run the buildInfo command:
buildInfoCmd := bson.D{bson.E{Key: "buildInfo", Value: 1}}
var buildInfoDoc bson.M
if err := db.RunCommand(ctx, buildInfoCmd).Decode(&buildInfoDoc); err != nil {
log.Printf("Failed to run buildInfo command: %v", err)
return
}
log.Println("Database version:", buildInfoDoc["version"])
Based on #icza's answer, here is how to obtain other metadata of the Database:
We need to use dbStats command to obtain metadata.
host := "<your-host-name>:<pot-number>"
url := "mongodb://" + host
credential := options.Credential{
AuthSource: "authentication-database",
Username: "username",
Password: "password",
}
clientOpts := options.Client().ApplyURI(url).SetAuth(credential)
ctx := context.Background()
client, err := mongo.Connect(ctx, clientOpts)
if err != nil {
log.Fatal("Failed to connect to db : %w", err)
}
defer client.Disconnect(ctx)
if err := client.Ping(context.TODO(), readpref.Primary()); err != nil {
panic(err)
}
fmt.Println("Successfully connected and pinged.")
db := client.Database("your-database-name")
dbStatsCmd := bson.D{bson.E{Key: "dbStats", Value: 1}}
var dbStatsDoc bson.M
if err := db.RunCommand(ctx, dbStatsCmd).Decode(&dbStatsDoc); err != nil {
log.Printf("Failed to run dbStats command: %v", err)
return
}
log.Println("\nTotal Used Size in MB: ", dbStatsDoc["totalSize"].(float64) / 1048576 , " ,Total Free size in MB (part of total used size): ", dbStatsDoc["totalFreeStorageSize"].(float64)/1048576)

Why I get an error "client disconnected" when trying to get documents from mongo collection in go?

I have mongo capped collection and a simple API, written on Go. I built and run it. When I try to sent Get request or simply go localhost:8000/logger in browser - my process closes. Debug shows this happens, while executing "find" in collection. It produces error "client is disconnected". Collection has 1 document, and debug shows it is connected with my helper.
Go version 1.13
My code:
func main() {
r := mux.NewRouter()
r.HandleFunc("/logger", getDocs).Methods("GET")
r.HandleFunc("/logger", createDoc).Methods("POST")
log.Fatal(http.ListenAndServe("localhost:8000", r))
}
func getDocs(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var docs []models.Logger
//Connection mongoDB with helper class
collection := helper.ConnectDB()
cur, err := collection.Find(context.TODO(), bson.M{})
if err != nil {
helper.GetError(err, w)
return
}
defer cur.Close(context.TODO())
for cur.Next(context.TODO()) {
var doc models.Logger
err := cur.Decode(&doc)
if err != nil {
log.Fatal(err)
}
docs = append(docs, doc)
}
if err := cur.Err(); err != nil {
log.Fatal(err)
}
json.NewEncoder(w).Encode(docs)
}
func ConnectDB() *mongo.Collection {
client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://127.0.0.1:27017"))
if err != nil {
log.Fatal(err)
}
fmt.Println("Connected to MongoDB!")
logCollection := client.Database("local").Collection("loggerCollection")
return logCollection
}
According to the documentation, the call to mongo.NewClient doesn't ensure that you can connect the Mongo server. You should first call mongo.Client.Ping() to verify if you can connect to the database or not.
client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://127.0.0.1:27017"))
if err != nil {
log.Fatal(err)
}
if err := client.Ping(context.TODO(), readpref.Primary()); err != nil {
// Can't connect to Mongo server
log.Fatal(err)
}
There could be several reasons behind failing to connect, the most obvious one is incorrect setup of ports. Is your mongodb server up and listening on port 27017? Is there any change you're running mongodb with Docker and it's not forwarding to the correct port?
I faced similar issue , read #Jay answer it definitely helped , as I checked my MongoDB was running using "MongoDB Compass" , then I changed the location of my insert statement , previously I was calling before the call of "context.WithTimeout". Below is working code.
package main
import (
"context"
"log"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type Book struct {
Name string `json:"name,omitempty"`
PublisherID string `json:"publisherid,omitempty"`
Cost string `json:"cost,omitempty"`
StartTime string `json:"starttime,omitempty"`
EndTime string `json:"endtime,omitempty"`
}
func main() {
client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017"))
if err != nil {
log.Fatal(err)
}
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
err = client.Connect(ctx)
if err != nil {
log.Fatal(err)
}
defer client.Disconnect(ctx)
testCollection := client.Database("BooksCollection").Collection("BooksRead")
inserRes, err := testCollection.InsertOne(context.TODO(), Book{Name: "Harry Potter", PublisherID: "IBN123", Cost: "1232", StartTime: "2013-10-01T01:11:18.965Z", EndTime: "2013-10-01T01:11:18.965Z"})
log.Println("InsertResponse : ", inserRes)
log.Println("Error : ", err)
}
I can see document inserted in console as well as in "MongoDB Comapass."
In heiper function "ConnectDB" after "NewClient" I must use "client.Connect(context.TODO())"
before any other use of client

MongoDB collection.Watch() compile and stop running

I'm newbie for MongoDB and I’ve tried to use collection.Watch() from "go.mongodb.org/mongo-driver/mongo" lib. and code from https://github.com/minhthuy30197/change_stream/blob/master/main.go. Then I build and run it stop immediately.
I’ve tried to run again and again and it also stop running. I’ve switch using between go run main.go and ./testStreams and it still stop running
So this is my edited code.
clientOptions := options.Client().
ApplyURI("mongodb://localhost:27017/test")
client, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil {
log.Fatalf("Failed to create the new client: %v", err)
}
ctx := context.Background()
if err := client.Connect(ctx); err != nil {
log.Printf("Failed to open client connection: %v", err)
}
defer client.Disconnect(ctx)
coll := client.Database("test").Collection("streams")
var pipeline interface{}
for {
cur, err := coll.Watch(ctx, pipeline)
if err != nil {
log.Fatalf("Watch error: %v", err)
}
defer cur.Close(ctx)
log.Println(cur)
for cur.Next(ctx) {
elem := CSElem{}
if err := cur.Decode(elem); err != nil {
log.Fatalf("Decode error: %v", err)
}
log.Println(elem)
}
if err := cur.Err(); err != nil {
log.Fatalf("Error detected: %v", err)
}
}
When I edit then error appear
2019/08/07 13:46:39 Failed to open client connection: topology is
connected or connecting exit status 1
How should I fix??
As mentioned on the comment, utilising mongo-go-driver v1+ a new client instance need to be created first before making a connection. For example:
clientOptions := options.Client().ApplyURI("mongodb://localhost:27017/test")
client, err := mongo.NewClient(clientOptions)
if err != nil {log.Fatal(err)}
// Timed out after 10 seconds of trying to connect
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
err = client.Connect(ctx)
if err != nil { log.Fatal(err)}

How to use new URL from mongodb 3.6 to connect from golang

I tried to connect to mongodb Atlas using golang drivers.
tlsConfig := &tls.Config{}
var mongoURI = "mongodb+srv://admin:password#prefix.mongodb.net:27017/dbname"
dialInfo, err := mgo.ParseURL(mongoURI)
if err != nil {
panic(err)
}
dialInfo.DialServer = func(addr *mgo.ServerAddr) (net.Conn, error) {
conn, err := tls.Dial("tcp", addr.String(), tlsConfig)
return conn, err
}
session, err := mgo.DialWithInfo(dialInfo)
if err != nil {
println("error")
log.Fatal(err)
}
_ = session
c := session.DB("Token").C("_Users")
user := &User{firstName: "username"}
err = c.Insert(user)
if err != nil {
println("error Again")
}
I am not getting an error not getting connected.
I am wondering what could be the reason.'
Any help is appreciated.
I tried to create DialInfo using below code
dialInfo := &mgo.DialInfo{
Addrs: []string{"prefix.mongodb.net:27017"},
Database: "dbname",
Mechanism: "SCRAM",
Timeout: 10 * time.Second,
Username: "admin",
Password: "passwrd",
}
Now I am getting no reachable servers
I could only see that the code started, then nothing
As you have figured out, this is because DialInfo by default has a zero timeout. The call will block forever waiting for a connection to be established. You can also specify a timeout with:
dialInfo.Timeout = time.Duration(30)
session, err := mgo.DialWithInfo(dialInfo)
Now I am getting no reachable servers
This is because globalsign/mgo does not currently support SRV connection string URI yet. See issues 112.
You can use the non-srv connection URI format (MongoDB v3.4), see a related question StackOverflow: 41173720.
You can use mongo-go-driver instead if you would like to connect using the SRV connection URI, for example:
mongoURI := "mongodb+srv://admin:password#prefix.mongodb.net/dbname?ssl=true&retryWrites=true"
client, err := mongo.NewClient(options.Client().ApplyURI(mongoURI))
if err != nil {
log.Fatal(err)
}
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
err = client.Connect(ctx)
defer client.Disconnect(ctx)
if err != nil {
log.Fatal(err)
}
database := client.Database("go")
collection := database.Collection("atlas")
The above example is compatible with the current version v1.0.0
For MongoDB Atlas
serverAPIOptions := options.ServerAPI(options.ServerAPIVersion1)
clientOptions := options.Client().
ApplyURI("mongodb://username:password#prefix0.mongodb.net:27017,prefix1.mongodb.net:27017,prefix2.mongodb.net:27017/?retryWrites=true&w=majority&replicaSet=atlas-zhqegh-shard-0&tls=true").
SetServerAPIOptions(serverAPIOptions)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
client, err := mongo.Connect(ctx, clientOptions)
if err != nil {
log.Fatal(err)
}
To clarify the MongoDB Atlas replicaSet and hosts you can for instance utilize MongoDB Compass: just connect to the cluster and you will see all that data.