I have this callback
p.OnSuccess(func(v interface{}) {
bulk := collections.Bulk()
bulk.Insert(v)
_, bulkErr := bulk.Run()
if bulkErr != nil {
panic(bulkErr)
}
fmt.Printf("\n - %d comments inserted!", reflect.ValueOf(v).Len())
Response(w, 200, 1, "comment inserted!", v)
})
Where v is a interface array and when i run the program for insert the data in mongo, golang response me with this message:
BSON field 'insert.documents.0' is the wrong type 'array', expected type 'obje
ct'
this is the struct:
type Comment struct {
CommentId int64 `bson:"commentId" json:"commentId"`
From UserComment `bson:"from" json:"from"`
Text string `bson:"text" json:"text"`
CreatedTime time.Time `bson:"createdTime" json:"createdTime"`
InfId string `bson:"infId" json:"infId"`
PostDate string `bson:"postDate" json:"postDate"`
PostId string `bson:"postId" json:"postId"`
Rate string `bson:"rate" json:"rate"`
CreatedAt time.Time `bson:"createdAt" json:"createdAt"`
UpdatedAt time.Time `bson:"updatedAt" json:"updatedAt"`
}
type UserComment struct {
InstagramId int64 `bson:"instagramId" json:"instagramId"`
Username string `bson:"username" json:"username"`
FullName string `bson:"fullName" json:"fullName"`
Picture string `bson:"picture" json:"picture"`
}
i don't know if is the format of the struct but i tried with this code and it did not work either!
var (
Allcomments []Comment
p = promise.NewPromise()
)
fc := UserComment{
InstagramId: 1121313, //c.User.ID,
Username: "c.User.Username",
FullName: "c.User.FullName",
Picture: "c.User.ProfilePicURL",
}
cmmnts := Comment{
CommentId: 44232323, //c.ID,
From: fc,
Text: "c.Text",
CreatedTime: now,
InfId: "infId",
PostDate: "postDate",
PostId: "PostId",
Rate: "a",
CreatedAt: now,
UpdatedAt: now,
}
Allcomments = append(Allcomments, cmmnts)
p.Resolve(Allcomments)
First, I would suggest to use go.mongodb.org/mongo-driver library to interact with MongoDB. This is the MongoDB official driver for the Go language.
To insert an array, you can utilise Collection.InsertMany(). For example:
result, err := coll.InsertMany(
context.Background(),
[]interface{}{
bson.D{
{"item", "shirt"},
{"quantity", int32(25)},
{"tags", bson.A{"blank", "red"}},
{"size", bson.D{
{"h", 14},
{"w", 21},
{"uom", "cm"},
}},
},
bson.D{
{"item", "hat"},
{"quantity", int32(42)},
{"tags", bson.A{"gray"}},
{"size", bson.D{
{"h", 27.9},
{"w", 35.5},
{"uom", "cm"},
}},
},
})
See also Collection.BulkWrite() to perform Bulk Write Operations
Related
How to update the document with non zero values only. As example I didn't received any value for status and Struct has only two values to be updated. So it should only update those 2 values and skip zero/null values. But as given below it's updating it to zero/null/""
type Product struct {
ID primitive.ObjectID `json:"id" bson:"_id"`
Status int `json:"status" bson:"status"`
DisplayName string `json:"displayName" bson:"display_name"`
Text string `json:"text" bson:"text"`
}
I have tried the following up it's overriding the status value to 0 if no value is passed for it.
opts := options.Update().SetUpsert(false)
filter := bson.D{primitive.E{Key: "_id", Value: product.ID}}
update := bson.D{{"$set", bson.D{{"status", product.Status}, bson.D{{"text",product.Text}, {"display_name", product.DisplayName}}}}
_, err := db.Collection("product").UpdateOne(context.TODO(), filter, update, opts)
How to achieve this cleanly without ifs. For any struct in Service.
First, your update document should not contain an embedded document if Product is the Go struct that models your documents. It should be:
update := bson.D{
{"$set", bson.D{
{"status", product.Status},
{"text", product.Text},
{"display_name", product.DisplayName},
}},
}
Now on to your issue. You explicitly tell in the update document to set them to their zero value, so that's what MongoDB does.
If you don't want to set zero values, don't add them to the update document. Build your update document like this:
setDoc := bson.D{}
if product.Status != 0 {
setDoc = append(setDoc, bson.E{"status", product.Status})
}
if product.Text != "" {
setDoc = append(setDoc, bson.E{"text", product.Text})
}
if product.DisplayName != "" {
setDoc = append(setDoc, bson.E{"display_name", product.DisplayName})
}
update := bson.D{{"$set", setDoc}}
Note that you can achieve the same if you use the ,omitempty BSON tag option and use / pass a Product struct value for the setDoc:
type Product struct {
ID primitive.ObjectID `json:"id" bson:"_id"`
Status int `json:"status" bson:"status,omitempty"`
DisplayName string `json:"displayName" bson:"display_name,omitempty"`
Text string `json:"text" bson:"text,omitempty"`
}
And then simply:
update := bson.D{{"$set", product}}
I have the following structure in my database:
{
"_id": {
"$oid": "5fc4fc68fcd604bac9f61f71"
},
"init": {
"fullname": "Besikta Anibula",
"parts": [
"Besikta",
"Anibula"
],
"alt": "Besikta Ani."
},
"industry": "E-Commerce"
}
I´m trying to just access the init object and write the results to a structured variable in Go:
var InputData struct {
Fullname string `bson:"fullname" json:"fullname"`
Parts []string`bson:"parts" json:"parts"`
Alt string `bson:"alt" json:"alt"`
}
collectionRESULTS.FindOne(ctx, options.FindOne().SetProjection(bson.M{"init": 1})).Decode(&InputData)
js, _ := json.Marshal(InputData)
fmt.Fprint(writer, string(js))
But the result is empty:
{"fullname":"","parts":null,"alt":""}
It is working when not using a projection like:
var InputData struct {
Ident primitive.ObjectID `bson:"_id" json:"id"`
}
collectionRESULTS.FindOne(ctx, bson.M{}).Decode(&InputData)
js, _ := json.Marshal(InputData)
fmt.Fprint(writer, string(js))
Result as expected:
{"id":"5fc4fc68fcd604bac9f61f71"}
You set the projection to only retrieve the init property of the result documents, and then you try to unmarshal into a struct value that does not have any matching field for the init value, so nothing will be set in that struct value.
You must use a value that has an init field, like this wrapper Result struct:
type Result struct {
Init InputData `bson:"init"`
}
type InputData struct {
Fullname string `bson:"fullname" json:"fullname"`
Parts []string `bson:"parts" json:"parts"`
Alt string `bson:"alt" json:"alt"`
}
Use it like this:
var result Result
err := collectionRESULTS.FindOne(ctx, bson.M{}, options.FindOne().
SetProjection(bson.M{"init": 1})).Decode(&result)
if err != nil {
// handle error
}
I am trying to save an array of numbers in a single postgresql field using Gorm.
The array needs to be a list with between 2 & 13 numbers: [1, 2, 3, 5, 8, 13, 21, 40, 1000]
Everything was working when saving a single int64. When I tried changing the model to account for an array of int64's it gives me the following error:
"panic: invalid sql type (slice) for postgres"
my Gorm model is:
type Game struct {
gorm.Model
GameCode string
GameName string
DeckType []int64
GameEndDate string
}
Update based on answer from #pacuna. I tried the suggested code and I get a similar error.
"panic: invalid sql type Int64Array (slice) for postgres"
Here is the full code block:
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/postgres"
pq "github.com/lib/pq"
)
var db *gorm.DB
// Test -- Model for Game table
type Test struct {
gorm.Model
GameCode string
GameName string
DeckType pq.Int64Array
GameEndDate string
}
func main() {
db, err := gorm.Open("postgres", "host=localhost port=5432 user=fullstack dbname=scratch_game sslmode=disable")
if err != nil {
fmt.Println(err.Error())
panic("Failed to connect to database...")
}
defer db.Close()
dt := []int64{1, 2, 3}
db.AutoMigrate(&Test{})
fmt.Println("Table Created")
db.Create(&Test{GameCode: "xxx", GameName: "xxx", DeckType: pq.Int64Array(dt), GameEndDate: "xxx"})
fmt.Println("Record Added")
}
You need to use custom types from the underlying library:
type Game struct {
gorm.Model
GameCode string
GameName string
DeckType pq.Int64Array `gorm:"type:integer[]"`
GameEndDate string
}
// example insertion
dt := []int64{1, 2, 3}
db.Create(&Game{GameCode: "xxx", GameName: "xxx", DeckType: pq.Int64Array(dt), GameEndDate: "xxx"})
i looking to check if exist item added in last 30 min in golang with mongodb.
this is my type models:
type PayCoin struct {
ID bson.ObjectId `json:"id" bson:"_id"`
OwnerID bson.ObjectId `json:"owner_id" bson:"owner_id"`
PublicKey string `json:"public_key" bson:"public_key"`
PrivateKey string `json:"-" bson:"private_key"`
QrCode string `json:"qrcode" bson:"-"`
ExchangeRate uint64 `json:"exchange_rate" bson:"exchange_rate"`
DepositAmount float32 `json:"deposit_amount" bson:"deposit_amount"`
Received uint64 `json:"received" bson:"received"`
Completed bool `json:"-" bson:"completed"`
CreatedAt time.Time `json:"created_at" bson:"created_at"`
UpdatedAt time.Time `json:"updated_at" bson:"updated_at"`
}
this is my current function :
func (s *Storage) CoinPayExistOperation(ownerID bson.ObjectId) (*models.PayCoin, error) {
collection := s.getCoinPay()
var lt models.PayCoin
timeFormat := "2006-01-02 15:04:05"
now := time.Now()
after := now.Add(-30*time.Minute)
nowFormated := after.Format(timeFormat)
err := collection.Find(bson.M{"owner_id": ownerID, "created_at": nowFormated}).One(<)
return <, err
}
i want to check if exist items in database added in last 30 min, my current code not return any item, and in database exist. How i can do this ?
You have two small things to fix here.
If you want to fetch various records you should change the word one by all
you are doing a filter where your data time is Greater than, for this, you have to use a comparison query operator $gt
here an example how your query should looks like
collection.Find(bson.M{"owner_id": ownerID, "created_at": bson.M{"$gt": nowFormated}}).All(<)
Note: as this will return multiple records, remember change the lt by an slice.
I am new to mongodb-go-driver and i am stuck.
I have a date inside a struct like:
type Email struct {
Date string `json:"date"`
}
the Dates on my mongoDB and mapped in my struct have the values like "02/10/2018 11:55:20".
I want to find on my DB the elements that Date are after an other date, i'm trying this but the response is always null.
initDate, _ := time.Parse("02012006", initialDate)
cursor, err := emails.Find(context.Background(), bson.NewDocument(bson.EC.SubDocumentFromElements("date", bson.EC.DateTime("$gt", initDate.Unix()))))
what am i doing wrong?
the Dates on my mongoDB and mapped in my struct have the values like "02/10/2018 11:55:20".
There are a number of ways you could do. The first, as mentioned on the comment, is to convert the string date into an actual date format. See also MongoDB Date. Storing date values in the proper date format is the recommended way for performance.
If you have a document:
{ "a": 1, "b": ISODate("2018-10-02T11:55:20Z") }
Using mongo-go-driver (current v1.2.x) you can do as below to find and compare using date:
initDate, err := time.Parse("02/01/2006 15:04:05", "01/10/2018 11:55:20")
filter := bson.D{
{"b", bson.D{
{"$gt", initDate},
}},
}
cursor, err := collection.Find(context.Background(), filter)
Please note the layout value in the example above for time.Parse(). It needs to match the string layout/format.
An alternative way, without converting the value is to use MongoDB Aggregation Pipeline. You can use $dateFromString operator to convert the string date into date then use $match stage to filter by date.
For example, given documents:
{ "a": 1, "b": "02/10/2018 11:55:20" }
{ "a": 2, "b": "04/10/2018 10:37:19" }
You can try:
// Add a new field called 'newdate' to store the converted date value
addFieldsStage := bson.D{
{"$addFields", bson.D{
{"newdate", bson.D{
{"$dateFromString", bson.D{
{"dateString", "$b"},
{"format", "%d/%m/%Y %H:%M:%S"},
}},
}},
}},
}
initDate, err := time.Parse("02/01/2006 15:04:05", "02/10/2018 11:55:20")
// Filter the newly added field with the date
matchStage := bson.D{
{"$match", bson.D{
{"newdate", bson.D{
{"$gt", initDate},
}},
}},
}
pipeline := mongo.Pipeline{addFieldsStage, matchStage}
cursor, err := collection.Aggregate(context.Background(), pipeline)
The unstable bsonx package in mongodb-go-driver has a DateTime Type.
You can add the field in your struct like this:
type Email struct {
Date bsonx.Val
}
To declare the struct use bsonx.DateTime(millis int64):
Email{
Date: bsonx.DateTime(time.Now().UnixNano()/1e6)
}
*time.Now().UnixNano()/1e6 basically gets the unix millis.
And you can convert it to time.Time with email.Date.Time()