Querying GORM database by its pq.StringArray attribute - postgresql

I have the following gorm.Model and I want to Query my Postgres database to return Confessions that have a specific category in their .Categories attribute, but I have no idea how to Query inside a pq.StringArray. Is there a work-around?
type Confession struct {
gorm.Model
User string `json:"User"`
Title string `json:"Title"`
Body string `json:"Body"`
Mood string `json:"Mood"`
Categories pq.StringArray `gorm:"type:varchar(64)[]" json:"Categories"`
}
And here is how I tried to query, but using the LIKE operator throws an error.
if categories != nil {
for _, cat := range categories {
tx = tx.Where("Categories LIKE ?", "%"+cat+"%")
}
}

Use <# for array contains. You can query using Query function of *sql.DB and get *sql.DB using tx.DB() in gorm
sel := "SELECT * FROM confessions WHERE $1 <# categories"
categories := []string{"cat1", "cat2"}
rows, err := tx.DB().Query(sel, pq.Array(categories))
Or try Gorm Raw SQL , but I won't sure it will work properly or not for array functions.
References:
PostgreSQL Array function here
ProtgreSQL Array use in golang here

The easiest solution to my problem was to use the .Where command as such
tx = tx.Where("categories && ?", pq.Array(categories))
This will return a gorm.DB so I can continue to chain actions. The && operator is to check for OVERLAPPING elements.

Related

How to use Find().Select().One() in go mongo-driver library

This code is working fine in go mgo library
result interface{}
err = getCollection.Find(bson.M{}).Select(bson.M{"_id": 1}).One(&result)
but I want to perform this using go mongo-driver library
I have tried below code but it is not working as the above one
err = getCollection.FindOne(ctx, bson.M{}, options.FindOne().SetProjection(bson.M{"_id": 1})).Decode(&result)
My test collection data is
example{
"_id":ObjectId(),
"Name":"qwert"
}
Anyone suggest me how can we achieve this in mongo-driver?
i can't comment on your question because i am new contributor here, i am using mongo-driver in my project now, i have tried to fetch only projection only some fields to be show up,
can you specific the argument on second for filtering ?
var (
opt options.FindOneOptions
modelStruct model.Person
)
filter := bson.M{"email": "hello#test.com"}
opt.SetProjection(bson.M{"name": 1})
err := collection.findOne(context.Background(), filter, opt).Decode(&modelStruct)
if that doesn't work, then you should limit the struct , make sure in your model.Person has data like this
type Person struct {
Name string `json:"name" bson:"name"`
Gender string `json:"gender" bson:"gender"`
}
or you can just make own model for limit the fields:
var personLimitOnlyGetName struct {
Name string `json:"name" bson:"name"`
}
// please look carefully in your collection field for camelCase
opt.SetProjection(bson.M{"name": 1})

Inserting string into jsonb type postgres

I have a function that generates a prepared statement for batch insert into postgres where I am trying to insert the string into type jsonb in postgres.
My struct looks like:
type struct1 struct {
id int
comment string
extra string
}
and my table schema looks like:
create table deal (
id bigserial,
comment varchar(75),
extra jsonb
)
and I want to dump []struct1 to Postgres DB "deal".
My function which generates the prepared statement looks like this:
func BulkInsert(str []struct1, ctx context.Context) string {
log.Debug("inserting records to DB")
query := fmt.Sprintf(`insert into deal (%s) values `, strings.Join(dbFields, ","))
var numFields = len(dbFields)
var values []interface{}
for i, database := range str {
values = append(values, database.Comment,`'`+database.Extra+`'`)
n := i * numFields
query += `(`
for j := 0; j < numFields; j++ {
query += `$` + strconv.Itoa(n+j+1) + `,`
}
query = query[:len(query)-1] + `),`
}
query = query[:len(query)-1]
return query
Expected results should be: I should be able to insert string to json or you can say cast string to json and dump it.
The actual result is :
could not save batch: pq: invalid input syntax for type json"
Function of json_build_array('exp1'::Text, 'exp2'::Text) may help you.
return json object: {'exp1', 'exp2'}
And extract the values just use operator ->><index> like ->>1 to get 'exp2'.
If you just want to insert into database, function of to_json('any element') should also works, which can convert any element to a json object.
And you can get more funtions about json(jsonb) in postgres document.

Convert a postgres row into golang struct with array field

I am having postgres db table as
CREATE TABLE foo (
name varchar(50),
types varchar(50)[],
role varchar[10]
);
and corresponding struct in go:
type Foo struct {
Name string `db:"name"`
Types []string `db:"types"`
Role string `db:"role"`
}
I want to fetch db rows into my struct. Right now I am able to do this by using:
var foo Foo
query := `SELECT name, types, roles FROM foo LIMIT 1`
err = dbConn.QueryRow(query).Scan(&foo.Name, pq.Array(&foo.Types), &foo.Role)
But I want to achieve the same using direct mapping. Something like:
var foo []Foo
query := `SELECT name, types, roles FROM foo`
dbWrapper.err = dbConn.Select(&foo, query)
Above snippet gives me error because of Types being pq array. Is it possible to directly map pq array as a part of struct?
Thanks to https://stackoverflow.com/a/44385791/10138004, I am able to solve this pq driver for sqlx (https://godoc.org/github.com/lib/pq) itself by replacing []string with pq.StringArray.
So, updated struct looks like:
type Foo struct {
Name string `db:"name"`
Types pq.StringArray `db:"types"` //this is what changed.
Role string `db:"role"`
}
and direct mapping is working like a charm now
var foo []Foo
query := `SELECT name, types, roles FROM foo`
dbWrapper.err = dbConn.Select(&foo, query)
You can use pg-go lib for that. Please look at pg.Model(). It's possible to pass an entire struct to it.

How to dynamically set table name for every query in go-pg?

I have a bunch of similar temp tables which I am trying to query using go-pg's ORM. I can't find a way to dynamically change the queried table during a select:
import "gopkg.in/pg.v4"
type MyModel struct {
TableName struct{} `sql:"temp_table1"`
Id int64
Name string
}
var mymodels []MyModel
err := db.Model(&mymodels).Column("mymodel.id", "mymodel.name").Select()
This will query temp_table1 as defined in the model's TableName. Is there a way to pass table name as a parameter so I can query temp_table_X?
(I can just not use ORM and go with raw db.Query(), but I wanted to see if there is a way to use ORM).
Got an answer on github:
err := db.Model().TableExpr("temp_table_999 AS mymodel").Column("mymodel.id", "mymodel.name").Select(&mymodels)
Seems you can specify the table directly: db.Model(&mymodels).Table('temp_table1').Column("mymodel.id", "mymodel.name").Select()

Obtain ObjectIdHex value from mgo query

I'm still new to go and while I see multiple questions on SO similar to this, I'm unable to reproduce the output some OP's had requested (this answer looking the closest).
I'm doing something fairly simple, I'm hitting a users collection in mongo and all I want to do is get the _id value back as a string. I'm going to eventually push these _id's up to NSQ but that's the brunt of my task.
var users []bson.M
err = sess.DB("db_name").C("users").Find(bson.M{}).All(&users)
if err != nil {
os.Exit(1)
}
for _, user := range users {
fmt.Printf("%+v \n", user["_id"])
}
Today this outputs:
ObjectIdHex("537f700b537461b70c5f0000")
ObjectIdHex("537f700b537461b70c600000")
ObjectIdHex("537f700b537461b70c610000")
ObjectIdHex("537f700b537461b70c620000")
I went through the bson#m docs and thought I was correctly using the map in order to extra the value. So I think, my query results in:
{"_id" : ObjectIdHex("Some_ID") }
but if ObjectIdHex("ID") is the value, how do I simply get the string within there.
So ideal output:
"537f700b537461b70c5f0000"
"537f700b537461b70c600000"
"537f700b537461b70c610000"
"537f700b537461b70c620000"
The value associated with key "_id" is of type bson.ObjectId which is simply a string.
bson.M is a type map[string]interface{}, so you need Type assertion to get the id as an ObjectId:
objid, ok := m["_id"].(ObjectId)
if !ok {
panic("Not ObjectId")
}
And the ObjectId has a ObjectId.Hex() method which returns exactly what you want: the object id as a "pure" hex string:
fmt.Println(objid.Hex())
Alternatives
objid can simply be converted to string because its underlying type is string. So you can use a number of further options to convert it to a hex string:
hexid := fmt.Sprintf("%x", string(objid))
If you just want to print it, you can do directly:
fmt.Printf("%x", string(objid))
Note: Converting it to string is important else the fmt package would call its String() method which results in a string like ObjectIdHex("537f700b537461b70c5f0000") and this is what would be converted to hex which is clearly not what you want.
Alternatively you can use the encoding/hex package and the hex.EncodeToString() function:
hexid := hex.EncodeToString([]byte(objid))