connection to remote mongodb server failed in golang, giving authentication error - mongodb

I am trying to connect to remote mongodb server in golang and adding data in database. Its giving me error as follows:
server returned error on SASL authentication step: Authentication failed.
Code:
package main
import (
"fmt"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"log"
// "os"
)
type Person struct {
Name string
Phone string
}
func main() {
session, err := mgo.Dial("mongodb://<dbuser>:<dbpassword>#ds041154.mongolab.com:41154/location")
if err != nil {
fmt.Println(err)
} else {
fmt.Println("Session created")
}
// Optional. Switch the session to a monotonic behavior.
session.SetMode(mgo.Monotonic, true)
c := session.DB("location").C("people")
err = c.Insert(&Person{"Ale", "+55 53 8116 9639"},
&Person{"Cla", "+55 53 8402 8510"})
if err != nil {
log.Fatal(err)
}
result := Person{}
err = c.Find(bson.M{"name": "Ale"}).One(&result)
if err != nil {
log.Fatal(err)
}
fmt.Println("Phone:", result.Phone)
}
Any help on this is appreciated.

I was getting similar error, but I found that I had entered wrong login credentials.
This code worked for me:
package main
import (
"fmt"
"time"
"gopkg.in/mgo.v2"
)
//const MongoDb details
const (
hosts = "ds026491.mongolab.com:26491"
database = "messagingdb"
username = "admin"
password = "youPassword"
collection = "messages"
)
func main() {
info := &mgo.DialInfo{
Addrs: []string{hosts},
Timeout: 60 * time.Second,
Database: database,
Username: username,
Password: password,
}
session, err1 := mgo.DialWithInfo(info)
if err1 != nil {
panic(err1)
}
col := session.DB(database).C(collection)
count, err2 := col.Count()
if err2 != nil {
panic(err2)
}
fmt.Println(fmt.Sprintf("Messages count: %d", count))
}
It is also on Github

You need to call .Login(user, pass string) on the database you need to authenticate with:
if err:= session.DB(authDB).Login(user, pass); err != nil {
panic(err)
}
Note that this authenticates the session, so each other session you .Copy() or .Clone() from it is also authenticated.

Related

How can i solve my Error by Connecting golang with MongoDB?

I have a problem with connecting the MongoDB to an API that is written in Golang. If you can help me, I would be really grateful. I don't find anything when I google it. To give a little context I am trying to complete this tutorial and in my opinion I have done it exactly like the guy from this medium post: https://medium.com/geekculture/build-a-rest-api-with-golang-and-mongodb-gin-gonic-version-6213083a86fe#id_token=eyJhbGciOiJSUzI1NiIsImtpZCI6ImIxYTgyNTllYjA3NjYwZWYyMzc4MWM4NWI3ODQ5YmZhMGExYzgwNmMiLCJ0eXAiOiJKV1QifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJuYmYiOjE2NTI0Mjc1NjAsImF1ZCI6IjIxNjI5NjAzNTgzNC1rMWs2cWUwNjBzMnRwMmEyamFtNGxqZGNtczAwc3R0Zy5hcHBzLmdvb2dsZXVzZXJjb250ZW50LmNvbSIsInN1YiI6IjExMDUzMzkxMjYxNjQ3MTI5NzcyOCIsImVtYWlsIjoiZWxpYWguZ2VyYmVyQGdtYWlsLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJhenAiOiIyMTYyOTYwMzU4MzQtazFrNnFlMDYwczJ0cDJhMmphbTRsamRjbXMwMHN0dGcuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJuYW1lIjoiRWxpYWggR2VyYmVyIiwicGljdHVyZSI6Imh0dHBzOi8vbGgzLmdvb2dsZXVzZXJjb250ZW50LmNvbS9hLS9BT2gxNEdpRXFEN1lzRFJBdTE2YWluUVkyQkVOQjhILUc5XzFCNEVvdElJQjB3PXM5Ni1jIiwiZ2l2ZW5fbmFtZSI6IkVsaWFoIiwiZmFtaWx5X25hbWUiOiJHZXJiZXIiLCJpYXQiOjE2NTI0Mjc4NjAsImV4cCI6MTY1MjQzMTQ2MCwianRpIjoiMzYxMzAwZjQyMDE4M2Q4MjU5MzY5ODQwNmNlYjY0YmE0MWE4NWJhZCJ9.llhfgrPC1LaGzaf6evc-AhUaMsSJl529gC_Uc5BA1o1X9zzz0xxPtACth719hmYukLgnpKeU3UFTi74fUfHBA3vmg-9QgJY2vUamiiZNOJ5ZcufJEUAd37mqsOBA2_xghsr34aTKypO741pBsx-LDOa7fcIwTyeTrgJL3pQAYYPyri7O27eEsW-Khb3SWhnYpjv-WB7Eph6c4_jyNeiWf6CFAhMl4Xl-gbMaTiT2YIF9W_oNfQQyZ7OPMi0w1l2_7wSIxbTRrrGs_mlXZgaM5lHVqTh32G9SVNpsV6GGC57a1zISioKLEgEgGrphQ-7BBJ89Jqv_uewM8jVOMaFt7Q
My error:
2022/05/13 12:24:55 server selection error: context deadline exceeded, current topology: { Type: ReplicaSetNoPrimary, Servers: [{ Addr: cluster0-shard-00-01.muyyt.mongodb.net:27017, Type: Unknown }, { Addr: cluster0-shard-00-02.m
uyyt.mongodb.net:27017, Type: Unknown }, { Addr: cluster0-shard-00-00.muyyt.mongodb.net:27017, Type: Unknown }, ] }
My Files:
.env
MONGOURI=mongodb+srv://eliah:1234#cluster0.muyyt.mongodb.net/myFirstDatabase?retryWrites=true&w=majority
env.go
package configs
import (
"github.com/joho/godotenv"
"log"
"os"
)
func EnvMongoURI() string {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
return os.Getenv("MONGOURI")
}
setup.go:
package configs
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"log"
"time"
)
func ConnectDB() *mongo.Client {
client, err := mongo.NewClient(options.Client().ApplyURI(EnvMongoURI()))
if err != nil {
log.Fatal(err)
}
ctx, _ := context.WithTimeout(context.Background(), 10*time.Second)
err = client.Connect(ctx)
if err != nil {
log.Fatal(err)
}
//ping the database
err = client.Ping(ctx, nil)
if err != nil {
log.Fatal(err)
}
fmt.Println("Connected to MongoDB")
return client
}
//Client instance
var DB *mongo.Client = ConnectDB()
//getting database collections
func GetCollection(client *mongo.Client, collectionName string) *mongo.Collection {
collection := client.Database("golangAPI").Collection(collectionName)
return collection
}
main.go:
package main
import (
"gin-mongo-api/configs" //add this
"github.com/gin-gonic/gin"
)
func main() {
router := gin.Default()
//run database
configs.ConnectDB()
router.Run("localhost:6000")
}

Postgres - Golang Error: pq: Users does not exists

I'm trying to connect Golang to a Postgres DB, it is in Gcloud and I already allowed the network IP. I'm trying to access the User DB and then the User table inside the public schema, this is the database structure:
I am getting this error: pq: database "Users" does not exist
I'll add the code:
package ports
import (
"database/sql"
"log"
"github.com/gofiber/fiber/v2"
_ "github.com/lib/pq"
)
func OpenConnection(dbName string) (*sql.DB, error) {
connStr := "<addr>" + dbName
db, err := sql.Open("postgres", connStr)
if err != nil {
log.Fatal(err)
}
return db, err
}
func GetUsers(ctx *fiber.Ctx) error {
db, dbErr := OpenConnection("Users")
if dbErr != nil {
log.Fatalln(dbErr)
}
defer db.Close()
rows, err := db.Query("SELECT * FROM Users")
if err != nil {
log.Fatalln(err)
ctx.JSON("An error ocurred")
}
defer rows.Close()
return ctx.Render("/users", fiber.Map{
"Users": rows,
})
}
I just fixed it and it was a combination of two things:
I wasn't properly combining the strings, when I hardcoded it I got rid of the db error.
After that I encountered an error where it would say the table doesn't exists, the issue is I was sending an unquote table name and I needed it to be case sensitive so I had to wrap the name between quotes to make it work. Like so
package ports
import (
"database/sql"
"log"
"github.com/gofiber/fiber/v2"
_ "github.com/lib/pq"
)
func OpenConnection() (*sql.DB, error) {
connStr := "<connStr>/users"
db, err := sql.Open("postgres", connStr)
if err != nil {
log.Fatal(err)
}
return db, err
}
func GetUsers(ctx *fiber.Ctx, db *sql.DB) error {
defer db.Close()
rows, err := db.Query(`SELECT * FROM "Users"`)
if err != nil {
log.Fatalln(err)
ctx.JSON("An error ocurred")
}
defer rows.Close()
return ctx.Render("/users", fiber.Map{
"Users": rows,
})
}

Go: client is disconnected

It's been few weeks since I joined in Gophers team. So far so good.
I started a new project using a fiber web framework to build backend APIs.
I am using MongoDB as my database.
database/db.go
package database
import (
"context"
"log"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
var DB *mongo.Database
// InitMongo : Initialize mongodb...
func connectToMongo() {
log.Printf("Initializing database")
client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017"))
if err != nil {
log.Fatal("Could not able to connect to the database, Reason:", err)
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
err = client.Connect(ctx)
if err != nil {
log.Fatal("Context error, mongoDB:", err)
}
//Cancel context to avoid memory leak
defer cancel()
defer client.Disconnect(ctx)
// Ping our db connection
err = client.Ping(context.Background(), readpref.Primary())
if err != nil {
log.Fatal("Ping, mongoDB:", err)
}
log.Printf("Database connected!")
// Create a database
DB = client.Database("golang-test")
return
}
// In Golang, init() functions always initialize whenever the package is called.
// So, whenever DB variable called, the init() function initialized
func init() {
connectToMongo()
}
controllers/mongo.controller/mongo.controller.go
package mongocontroller
import (
"log"
"github.com/gofiber/fiber/v2"
service "gitlab.com/.../services/mongoservice"
)
// GetPersons godoc
// #Summary Get persons.
// #Description Get persons
// #Tags persons
// #Produce json
// #Success 200 {object} []service.Person
// #Failure 400 {object} httputil.HTTPError
// #Failure 404 {object} httputil.HTTPError
// #Failure 500 {object} httputil.HTTPError
// #Router /v1/persons [get]
func GetPersons(c *fiber.Ctx) error {
res, err := service.GetPersons()
if err != nil {
log.Fatal("ERROR: in controller...", err)
}
return c.JSON(res)
}
services/mongoservice/mongo.service.go
package mongoservice
import (
"context"
"log"
database "gitlab.com/.../database"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
// Person : ...
type Person struct {
ID primitive.ObjectID `bson:"_id,omitempty" json:"_id,omitempty"`
Name string `bson:"name,omitempty" json:"name,omitempty"`
Age int `bson:"age,omitempty" json:"age,omitempty"`
}
func GetPersons() ([]Person, error) {
ctx := context.Background()
persons := []Person{}
log.Printf("mongo data...", ctx)
cur, err := database.DB.Collection("persons").Find(ctx, bson.M{})
if err != nil {
log.Fatal(err)
}
// Iterate through the returned cursor.
for cur.Next(ctx) {
var person Person
cur.Decode(&person)
persons = append(persons, person)
}
defer cur.Close(ctx)
return persons, err
}
Here is my data stored in the database:
The problem is, the line cur, err := database.DB.Collection("persons").Find(ctx, bson.M{}) from service always throwing Client is disconnected.
Any help is appreciated!
Thank you.
You are calling defer client.Disconnect(ctx) in the same function which is creating the connection (connectToMongo ) so it will close the connection after calling the function. You should return the connection and close after finishing your task. I mean these parts:
defer cancel()
defer client.Disconnect(ctx)

Connection(localhost:27017[-4]) failed to write: context canceled

Here I read it's necessary to cancel the context. This is how my db.go looks like:
package db
import (
"context"
"fmt"
"log"
"os"
"time"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
const (
connectionStringTemplate = "mongodb://%s:%s#%s"
)
var DB *mongo.Client
var Ctx context.Context
// Connect with create the connection to MongoDB
func Connect() {
username := os.Getenv("MONGODB_USERNAME")
password := os.Getenv("MONGODB_PASSWORD")
clusterEndpoint := os.Getenv("MONGODB_ENDPOINT")
connectionURI := fmt.Sprintf(connectionStringTemplate, username, password, clusterEndpoint)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
client, err := mongo.NewClient(options.Client().ApplyURI(connectionURI))
if err != nil {
log.Printf("Failed to create client: %v", err)
}
err = client.Connect(ctx)
if err != nil {
log.Printf("Failed to connect to cluster: %v", err)
}
// Force a connection to verify our connection string
err = client.Ping(ctx, nil)
if err != nil {
log.Printf("Failed to ping cluster: %v", err)
}
DB = client
Ctx = ctx
log.Printf("Connected to MongoDB!")
}
I execute this in the main.go:
func main() {
// Configure
db.Connect()
defer db.DB.Disconnect(context.Background())
r := gin.Default()
// Routes
//r.GET("/movies", handlers.GetAllMoviesHandler)
r.POST("/movies", handlers.AddMovieHandler)
// listen and serve on 0.0.0.0:8080
r.Run()
}
and it works fine if my local mongodb is running.
Now when I use the client like this (I know the naming is still bad):
func AddMovie(movie *Movie) (primitive.ObjectID, error) {
movie.ID = primitive.NewObjectID()
result, err := db.DB.Database("movies").Collection("movies").InsertOne(db.Ctx, movie)
if err != nil {
log.Printf("Could not create movie: %v", err)
return primitive.NilObjectID, err
}
oid := result.InsertedID.(primitive.ObjectID)
return oid, nil
}
I get an error like this
{"msg":{"Code":0,"Message":"connection(localhost:27017[-4]) failed to write: context canceled","Labels":["NetworkError","RetryableWriteError"],"Name":"","Wrapped":{"ConnectionID":"localhost:27017[-4]","Wrapped":{}}}}
It works fine when I put the defer cancel() in comment but I suppose this is not correct?. What am I doing wrong here.
Update:
It works when I use:
result, err :=db.DB.Database("movies").Collection("movies").InsertOne(context.Background(), movie) instead of ctx. I don't fully understand the usage of the context in these use case. I'm not sure if I should do the Ctx = ctx in the Connect function either.

Cannot return database object.

This is my code for working with postgres database.
package main
import (
"database/sql"
_ "github.com/lib/pq"
"fmt"
"log"
)
//Details required for connection
const (
HOST = "HOSTNAME"
USER = "USER"
PASSWORD = "PASSWORD"
DATABASE = "DB"
)
func Create() (*sql.DB) {
dbinfo := fmt.Sprintf("host=%s user=%s password=%s dbname=%s", HOST, USER, PASSWORD, DATABASE)
db,err := sql.Open("postgres", dbinfo)
defer db.Close()
if (err != nil) {
log.Fatal(err)
}
err = db.Ping()
if err != nil {
log.Fatal(err)
}
return db
}
func main() {
db := Create()
querStmt, err := db.Prepare("select count(*) from table")
if err != nil {
fmt.Printf("Cannot prepare query\n")
log.Fatal(err)
}
res, err := querStmt.Exec()
if err != nil {
fmt.Printf("Cannot execute query\n")
log.Fatal(err)
}
fmt.Printf("%v\n", res)
}
When running this code i am getting this error
Cannot prepare query
2016/03/09 16:57:23 sql: database is closed
If i run query from Create() then it works perfectly but doing same on db object returned by Create() inside main() is not working. Thanks for help.
Your database is closed the moment you return from Create because your defer is inside it and not inside main. Move the defer to main and it should work as intended.