I need to save the timestamps for createdAt and updatedAt properties in the database, but they are not being saved automatically, they are being saved as {T: 0, I: 0}. I am using Mongo Driver to perform CRUD operations.
So, this leds me to another problem while attaching the current time to the user model; I read somewhere that both createdAt and updatedAt have to be primitive.Timestamp, but I don't know how to really save them.
I have tried User.CreatedAt = with:
time.Now()
new primitive.Timestamp(time.Now(), 1))
primitive.Timestamp{ T: uint32(time.Now().Unix()), I: 0 } (this seems to be working)
Getting back to the main problem, the best solution should be that the database allows me to configure the timestamps to be saved automatically whenever a insertOne() is triggered.
That could work always that assigning primitive.Timestamp to User.CreatedAt is correct.
So, this is my model:
package models
import (
"go.mongodb.org/mongo-driver/bson/primitive"
)
type User struct {
Id primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
Email string `bson:"email" json:"email"`
CreatedAt primitive.Timestamp `bson:"createdAt" json:"createdAt"`
UpdatedAt primitive.Timestamp `bson:"updatedAt" json:"updatedAt"`
}
And this is my service:
func CreateUser(user models.User) (models.User, error) {
db := database.GetDatabase()
result, err := db.Collection(collection).InsertOne(context.TODO(), user)
if err != nil {
return models.User{}, err
}
user.Id = result.InsertedID.(primitive.ObjectID)
user.CreatedAt = primitive.Timestamp{ T: uint32(time.Now().Unix()), I: 0 }
return user, nil
}
So, it is ok to manage the timestamps like this or did I just mistaken?
You can simply use time.Time:
type User struct {
Id primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"`
Email string `bson:"email" json:"email"`
CreatedAt time.Time `bson:"createdAt" json:"createdAt"`
UpdatedAt time.Time `bson:"updatedAt" json:"updatedAt"`
}
MongoDB does not update these for you. You have to set them yourself before storing them in the DB:
user.CreatedAt=time.Now()
user.UpdatedAd=user.CreatedAt
result, err := db.Collection(collection).InsertOne(context.TODO(), user)
Related
type User struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
CreatedAt time.Time `bson:"created_at"`
UpdatedAt time.Time `bson:"updated_at"`
Name string `bson:"name"`
}
user := User{Name: "username"}
client.Database("db").Collection("collection").InsertOne(context.Background(), user)
How to use automated created_at and updated_at in the above code with mongodb(mongodb driver only) in golang? Currently it will set zero time(0001-01-01T00:00:00.000+00:00) for created_at and updated_at.
The MongoDB server does not support this.
You may implement a custom marshaler in which you may update these fields to your liking. Implement bson.Marshaler, and your MarshalBSON() function will be called when you save values of your *User type.
This is how it would look like:
func (u *User) MarshalBSON() ([]byte, error) {
if u.CreatedAt.IsZero() {
u.CreatedAt = time.Now()
}
u.UpdatedAt = time.Now()
type my User
return bson.Marshal((*my)(u))
}
Note the method has pointer receiver, so use a pointer to your value:
user := &User{Name: "username"}
c := client.Database("db").Collection("collection")
if _, err := c.InsertOne(context.Background(), user); err != nil {
// handle error
}
The purpose of the my type is to avoid stack overflow.
type User struct {
ID primitive.ObjectID `bson:"_id,omitempty"`
CreatedAt time.Time `bson:"created_at"`
UpdatedAt time.Time `bson:"updated_at"`
Name string `bson:"name"`
}
user := User{Name: "username"}
client.Database("db").Collection("collection").InsertOne(context.Background(), user)
How to use automated created_at and updated_at in the above code with mongodb(mongodb driver only) in golang? Currently it will set zero time(0001-01-01T00:00:00.000+00:00) for created_at and updated_at.
The MongoDB server does not support this.
You may implement a custom marshaler in which you may update these fields to your liking. Implement bson.Marshaler, and your MarshalBSON() function will be called when you save values of your *User type.
This is how it would look like:
func (u *User) MarshalBSON() ([]byte, error) {
if u.CreatedAt.IsZero() {
u.CreatedAt = time.Now()
}
u.UpdatedAt = time.Now()
type my User
return bson.Marshal((*my)(u))
}
Note the method has pointer receiver, so use a pointer to your value:
user := &User{Name: "username"}
c := client.Database("db").Collection("collection")
if _, err := c.InsertOne(context.Background(), user); err != nil {
// handle error
}
The purpose of the my type is to avoid stack overflow.
How do I set TTL indexes in a document using "mongo-go-driver"?
suppose here is my document model:
type Session struct {
ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
AccessToken string `json:"access_token" bson:"access_token"`
ExpireOn int64 `json:"expire_on" bson:"expire_on"`
}
and here I am inserting new document:
sessionCollection := database.Collection(COLLECTION_SESSION)
_, err = sessionCollection.InsertOne(context.TODO(), s)
if err != nil {
responses.RespondWithERROR(w, http.StatusInternalServerError, err)
return
}
Now I want that this session will be removed after a few times.
I found the way to do that in documentation Expire Data from Collections by Setting TTL but can't figure out How to do the same thing in go using mongo-go-driver.
I am using official MongoDb Driver for Golang. I have a field with timestamp type which I want to update from my Golang code.
This is my struct (lastUpdate field is the timestamp field):
import (
"context"
"log"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type MyStruct struct {
Id primitive.ObjectID `json:"id" bson:"_id,omitempty"`
Name string `json:"name"`
Alias string `json:"alias"`
Signed bool `json:"signed"`
Age int `json:"age"`
CreatedDate time.Time `json:"createdDaate"`
LastUpdate primitive.Timestamp `json:"lastUpdate"`
}
Then I pass this bson to update my data:
// logic to update data
docID, _ := primitive.ObjectIDFromHex("5de30185e4fabe4778f0ffdf")
UpdateMyData(c, bson.M{"createdDate": time.Now(), "lastUpdate": time.Now().UnixNano() }, bson.M{"_id": docID})
//update method
func UpdateMyData(client *mongo.Client, updatedData bson.M, filter bson.M) int64 {
collection := client.Database("*****").Collection("*****")
atualizacao := bson.D{ {Key: "$set", Value: updatedData} }
updatedResult, err := collection.UpdateOne(context.TODO(), filter, atualizacao)
if err != nil {
log.Fatal("Error on updating one Hero", err)
}
return updatedResult.ModifiedCount
}
The content of UpdateMyData method is fine cause it simply accepts bson and call UpdateOne method to update data into database and works for all different fields I have properly.
The problem is time.Now().UnixNane() returning int64 value, the above code does not throw an error, but it changes the "type" of lastUpdated to Int64 inside my MongoDb database for that specific row! So what is the correct way of passing data into timestamp field, without changing its type?
Try passing a timestamp instead of int64:
"lastUpdate": primitive.Timestamp{T:uint32(time.Now().Unix())}
Note that mongodb timestamp is unix seconds, not nanoseconds.
I have the following struct
type Account struct {
ID primitive.ObjectID `json:"id" bson:"_id"`
Email string `json:"email"`
Password string `json:"password"`
}
and the following function
func (a *Account) Create() map[string]interface{} {
if resp, ok := a.Validate(); !ok {
return resp
}
hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(a.Password), bcrypt.DefaultCost)
a.Password = string(hashedPassword)
users := db.Collection("users")
insertResult, err := users.InsertOne(context.TODO(), a)
if err != nil {
return utils.Message(false, "Error inserting user document "+err.Error())
}
... more code down hre
}
The problem I am having is that I can insert the first account, but any account after that can't be inserted due to a dup key error on the _id field. I know that mongoDB will auto generate an _id field and will use the one provided if there is an id. In my case in this create function, the a.ID (_id) is always be NilValue "_id" : ObjectId("000000000000000000000000")
Is there any way mongoDB can generate an _id for me even if I provide and ID field with the nil value?
I need the Account.ID `bson: "_id"` property on there so I can decode it when I am reading from mongoDB such as
func GetUser(email string) *Account {
account := &Account{}
users := db.Collection("users")
filter := bson.D{{"email", email}}
if err := users.FindOne(context.TODO(), filter).Decode(&account); err != nil {
return utils.Message(false, "Error Retrieving account for "+email)
}
// account.ID will be available due to the bson tag
}
I'd appreciate some feedback if I am doing this wrong and how I could do this better.
Thanks!
I found the problem. I did not add ```omitempty` to the bson tag.
It should be
type Account struct {
ID primitive.ObjectID `json:"id" bson:"_id,omitempty"`
Email string `json:"email"`
Password string `json:"password"`
}