mgo golang doesnt update empty array using $set - mongodb

struct and method:
type Group struct {
Id int64 `bson:"_id,omitempty"`
MediaFilterExceptionUserIds []int `bson:"media_filter_exception_user_ids,omitempty"`
}
func (g *Group) Save() error {
return DB.C("groups").UpdateId(g.Id, bson.M{"$set": &g})
}
func (g *Group) FindById() error {
return DB.C("groups").FindId(g.Id).One(&g)
}
trying to set media_filter_exception_user_ids to an empty []int{} and it doesn't work:
group := Group{}
group.FindById(123)
group.MediaFilterExceptionUserIds = []int{}
group.Save()
It works when there's an item inside the slice, but empty slice is not set.

MediaFilterExceptionUserIds type should change from []int to *[]int,
type Group struct {
Id int64 `bson:"_id,omitempty"`
MediaFilterExceptionUserIds *[]int `bson:"media_filter_exception_user_ids,omitempty"`
}
and then
group.MediaFilterExceptionUserIds = &[]int{}
will set it to an empty array in mongodb

Related

Using MongoDB Projection

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
}

bson.M {} deepequal does not seem to hande int32

I have a function for comparing two structs and making a bson document as input to mongodb updateOne()
Example struct format
type event struct {
...
Name string
StartTime int32
...
}
Diff function, please ignore that I have not checked for no difference yet.
func diffEvent(e event, u event) (bson.M, error) {
newValues := bson.M{}
if e.Name != u.Name {
newValues["name"] = u.Name
}
if e.StartTime != u.StartTime {
newValues["starttime"] = u.StartTime
}
...
return bson.M{"$set": newValues}, nil
}
Then I generated a test function like so:
func Test_diffEvent(t *testing.T) {
type args struct {
e event
u event
}
tests := []struct {
name string
args args
want bson.M
wantErr bool
}{
{
name: "update startime",
args: args{
e: event{StartTime: 1},
u: event{StartTime: 2},
},
want: bson.M{"$set": bson.M{"starttime": 2}},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := diffEvent(tt.args.e, tt.args.u)
if (err != nil) != tt.wantErr {
t.Errorf("diffEvent() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("diffEvent() = %v, want %v", got, tt.want)
}
})
}
}
This fails with a
--- FAIL: Test_diffEvent/update_startime (0.00s)
models_test.go:582: diffEvent() = map[$set:map[starttime:2]], want map[$set:map[starttime:2]]
For me this seem to be the same. I have played around with this and bool fields, string fields, enum fields, and fields as struct or fields as arrays of structs seems to work fine with deepequal, but it gives an error for int32 fields.
As a go beginner; what am I missing here? I would assume that if bool/string works then int32 would too.
This:
bson.M{"starttime": 2}
Sets the "starttime" key to the value of the literal 2. 2 is an untyped integer constant, and since no type is provided, its default type will be used which is int.
And 2 values stored in interface values are only equal if the dynamic value stored in them have identical type and value. So a value 2 with int type cannot be equal to a value 2 of type int32.
Use explicit type to tell you want to specify a value of int32 type:
bson.M{"starttime": int32(2)}

How to insert unmarshalled xml to mongodb

Here is my struct to unmarshall xml:
type parseStruct struct {
First string `xml:"CharCode"`
Second string `xml:"Value"`
}
type xmlParse struct {
Data []parseStruct `xml:"Valute"`
}
Result:
{[{AA 30.2070000} {AB 29.9378} {AC 30.0260} {AD 30.3702}]}
How should i insert this construction to mongoDB?
I'm trying it
It is my mongo struct
type result struct{
First string
Second string
}
Here is insert operation
for i, _ := range unm.Data {
collection.Insert(result{
Curr1: unm.Data[i].First,
Rate: unm.Data[i].Second,
})
fmt.Println("result", dataBatt.Data2[i].Rate, dataBatt.Data2[i].Curr1)
}
But if i need put to add to mongodb base other unmarshalled structure, similar to it but from other structure for example:
type parseSecondStruct struct {
First string `xml:"Char"`
Second string `xml:"Val"`
}
type xmlParse struct {
Data []parseSecondStruct `xml:"Valute"`
}
How should i paste 2 unrmashalled result in result struct and know where is result from 1 source and where is from 2.

Inserting struct in mongodb in Golang

I am trying to insert a struct in mongo database.
type SecretsStruct struct {
UserID string `bson:"userid" json:"userid"`
secretOne string `bson:"secret_one" json:secret_one`
secretTwo string `bson:"secret_two" json:secret_two`
secretThree string `bson:"secret_three" json:secret_three`
}
func (c *SecretsStruct) SetSecrets(userId string, encryptedKeys
[][]byte){
c.UserID = userId
c.secretOne = hex.EncodeToString(encryptedKeys[0])
c.secretTwo = hex.EncodeToString(encryptedKeys[1])
c.secretThree = hex.EncodeToString(encryptedKeys[2])
log.Printf("This is the c %s", c)
}
g := SecretsStruct{}
g.SetSecrets(userStruct.UserID, encryptedKeys)
err = secretCollection.Insert(g)
if err != nil {
panic(err)
}
I have tried inserting the byte arrays corresponding to the secrets but of no help. The result which gets populated to the corresponding insertion operation is :
{'_id': ObjectId('5b80117c118c660aaa0c87c2'),
'userid': 'eb19d220-ef13-43aa-8a7f-f78637718000'}
On the other hand, if I try to insert same data with a map but without struct.
secretCollection.Insert(bson.M{"userid": userStruct.UserID,
"secret_one": encryptedKeys[0],
"secret_two": encryptedKeys[1],
"secret_three": encryptedKeys[2]})
The insertion operation executes successfully.
You have to export your struct fields, so that another package (in this case mgo) can access them:
type SecretsStruct struct {
UserID string `bson:"userid" json:"userid"`
SecretOne string `bson:"secret_one" json:secret_one`
SecretTwo string `bson:"secret_two" json:secret_two`
SecretThree string `bson:"secret_three" json:secret_three`
}

MGO - empty results returned from Mongo that has results

I have a GOLANG struct as follows:
type OrgWhoAmI struct {
FriendlyName string `json:"friendlyName"`
RedemptionCode string `json:"redemptionCode"`
StartUrls []StartUrl `json:"startUrls"`
Status string `json:"status"`
Children []OrgChildren `json:"childrenReemptionCodes"`
}
type StartUrl struct {
DisplayName string `json:"displayName"`
URL string `json:"url"`
}
type OrgChildren struct {
FriendlyName string `json:"childFriendlyName"`
RedemptionCode string `json:"childRedemptionCode"`
}
I've created and successfully inserted records into a MongoDB collection (as I can see the results by querying Mongo with the CLI mongo program) - but when I query with MGO as follows, I get nothing:
func main() {
session, sessionErr := mgo.Dial("localhost")
defer session.Close()
// Query All
collection := session.DB("OrgData").C("orgWhoAmI")
var results []OrgWhoAmI
err = collection.Find(bson.M{}).All(&results)
if err != nil {
panic(err)
}
for _, res := range results {
fmt.Printf("Result: %s|%s\n", res.FriendlyName, res.RedemptionCode)
}
}
The results printed are:
Result: |
Result: |
Result: |
Result: |
If I ask for the count for records, I get the correct number, but all values for all fields are blank. Not sure what I'm missing here.
If you aren't creating them in go, it's probably not serializing the key names for you properly. The default for bson is to lowercase the keys, so you need to specify it if you want something else. Also note that you have a typo in OrgWhoAmI for json:"childrenReemptionCodes" (should be Redemption, I'm guessing). You can specify both bson and json separately if you want them to be different.
type OrgWhoAmI struct {
FriendlyName string `bson:"friendlyName" json:"friendlyName"`
RedemptionCode string `bson:"redemptionCode" json:"redemptionCode"`
StartUrls []StartUrl `bson:"startUrls" json:"startUrls"`
Status string `bson:"status" json:"status"`
Children []OrgChildren `bson:"childrenRedemptionCodes" json:"childrenRedemptionCodes"`
}
type StartUrl struct {
DisplayName string `bson:"displayName" json:"displayName"`
URL string `bson:"url" json:"url"`
}
type OrgChildren struct {
FriendlyName string `bson:"childFriendlyName" json:"childFriendlyName"`
RedemptionCode string `bson:"childRedemptionCode" json:"childRedemptionCode"`
}