Golang 中操作 Mongo Update 的方法

Golang 和 MongoDB 中的 ISODate 时间交互问题

2018年02月27日 11:28:43 独一无二的小个性 阅读数:357 标签: GolangMongoDB时间交互时间转换 更多

个人分类: MongoDBGolang

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010649766/article/details/79385948

MongoDB 中有一种时间格式数据 ISODate,参考如下: 

如果在 Golang 中查询这条记录,Golang用什么类型的变量来保存呢?

查找 ISODate 时间字段

在 Golang 中可以使用 time.Time 数据类型来保存 MongoDB 中的 ISODate 时间。

type Model struct {
    Id   bson.ObjectId `bson:"_id,omitempty"`
    Time time.Time     `bson:"time"`
}
m := Model{}
err := c.Find(bson.M{"_id": bson.ObjectIdHex("572f3c68e43001d2c1703aa7")}).One(&m)
if err != nil {
    panic(err)
}
fmt.Printf("%+v\n", m)
// output: {Id:ObjectIdHex("572f3c68e43001d2c1703aa7") Time:2015-07-08 17:29:14.002 +0800 CST}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

从输出中可以看到 Golang 输出的时间格式是 CST 时区,Golang 在处理的过程中将 ISO 时间转换成了 CST 时间,从时间面板上来看也比 MongoDB 中的快上 8 个小时,这个是正常的。

那么 Golang 做插入操作和或者时间比较操作的时候需要自己转换时间戳吗?答案是不需要的,来看下插入的例子。

插入时间

重新插入一条记录,记录的Time字段为当前时间,在golang中可以通过time.Now获取当前时间,查看输出可以看到是CST的时间格式

now := time.Now()
fmt.Printf("%+v\n", now)
// output: 2016-05-12 14:34:00.998011694 +0800 CST
err = c.Insert(Model{Time: now})
if err != nil {
    panic(err)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

查看 MongoDB 中的记录

插入当前时间到 MongoDB: 

可以看到存储到 MongoDB 中时间的自动转换为了 ISO 时间,时间少了 8 个小时。小结一下就是 Golang 和 MongoDB 中的时间交互不需要考虑额外的东西,因为驱动都进行了转换。

时间字符串转成 time.Time

有时我们会将 time.Time 的时间以字符串的形式存储,那么要和 MongoDB 交互的时候就需要转换 time.Time 格式

// 时间字符串转到到time.Time格式
// 使用time.Parse方法进行转换
timeString := "2016-05-12 14:34:00.998011694 +0800 CST"
t, err := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", timeString)
if err != nil {
    panic(err)
}
fmt.Printf("%+v\n", t)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

代码中比较难理解的就是 time.Parse 的第一个参数,这个其实是 Golang 当中的定义,详细看下 time.Time.String() 的源码就会明白了。

这篇博客主要记录下 Golang 中引入 Mongo 数据库对 Mongo 的修改操作的方法。

使用gopkg.in/mgo.v2库操作,修改操作主要使用mongodb中Collection对象的Update、UpdateAll、UpdateId、Upsert、UpsertId方法。

统一封装下getDB方法

package main

import (
    "fmt"

    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
)

// get mongodb db
func getDB() *mgo.Database {
    session, err := mgo.Dial("127.0.0.1:27017")
    if err != nil {
        panic(err)
    }
    session.SetMode(mgo.Monotonic, true)
    db := session.DB("test")
    return db
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

Update修改单条记录

func (c *Collection) Update(selector interface{}, update interface{}) error
  • 1

和mysql不同,Update函数只能用来修改单条记录,即使条件能匹配多条记录,也只会修改第一条匹配的记录。

selector := bson.M{"_id": bson.ObjectIdHex("56fdce98189df8759fd61e5b")}
data := bson.M{"age": 21}
err := getDB().C("user").Update(selector, data)
if err != nil {
    panic(err)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

类似于mongodb语法:

db.getCollection(‘user‘).update(
      { "_id": ObjectId("56fdce98189df8759fd61e5b") },
      { "age": 21}
  )
  • 1
  • 2
  • 3
  • 4

这边有一个小坑,就是这种写法的修改数据会更新整个文档为 {“age”: 21},而不是只更新age的值。

 更新前数据:
    {
        "_id" : ObjectId("56fdce98189df8759fd61e5b"),
        "name" : "Tom",
        "age" : 20
    }
 更新后数据:
    {
        "_id" : ObjectId("56fdce98189df8759fd61e5b"),
        "age" : 21
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

如果需要只更新age的值,则需要使用$set关键词:

selector := bson.M{"_id": bson.ObjectIdHex("571de968a99cff2c68264807")}
data := bson.M{"$set": bson.M{"age": 21}}
err := getDB().C("user").Update(selector, data)
if err != nil {
    panic(err)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如果更新的数据不存在,则会报一个not found的错误:

// 更新不存在的数据
selector := bson.M{"_id": bson.ObjectIdHex("16fdce98189df8759fd61e5b")}
data := bson.M{"age": 21}
err := getDB().C("user").Update(selector, data)
if err != nil {
    fmt.Println(err == mgo.ErrNotFound)
    // output: true
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

由于Update只能更新一条数据,如果需要批量更新则需要使用UpdateAll函数

UpdateAll批量更新

func (c *Collection) UpdateAll(selector interface{}, update interface{}) (info *ChangeInfo, err error)
  • 1
  • 2
selector := bson.M{"name": "Tom"}
data := bson.M{"$set": bson.M{"age": 22}}
changeInfo, err := getDB().C("user").UpdateAll(selector, data)
if err != nil {
    panic(err)
}
fmt.Printf("%+v\n", changeInfo)
// output: &{Updated:2 Removed:0 UpsertedId:<nil>}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

UpdateId根据Id更新 
和Update函数类似,就是条件直接换成了objectid,这个使用也挺频繁的。

func (c *Collection) UpdateId(id interface{}, update interface{}) error
类似
err := collection.Update(bson.M{"_id": id}, update)    
  • 1
  • 2
  • 3
id := bson.ObjectIdHex("571de968a99cff2c68264807")
data := bson.M{"$set": bson.M{"age": 30}}
err := getDB().C("user").UpdateId(id, data)
if err != nil {
    panic(err)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Upsert更新或者插入数据 
这个函数就是如果数据存在就更新,否则就新增一条记录。这个函数也挺常用的。

func (c *Collection) Upsert(selector interface{}, update interface{}) (info *ChangeInfo, err error)
  • 1
selector := bson.M{"key": "max"}
data := bson.M{"$set": bson.M{"value": 30}}
changeInfo, err := getDB().C("config").Upsert(selector, data)
if err != nil {
    panic(err)
}
fmt.Printf("%+v\n", changeInfo)
// 首次执行output: &{Updated:0 Removed:0 UpsertedId:ObjectIdHex("571df02ea99cff2c6826480a")}
// 再次执行output: &{Updated:1 Removed:0 UpsertedId:<nil>}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

UpsertId按照更新或者插入数据

 func (c *Collection) UpsertId(id interface{}, update interface{}) (info *ChangeInfo, err error)
 类似
 info, err := collection.Upsert(bson.M{"_id": id}, update)
  • 1
  • 2
  • 3
id := bson.ObjectIdHex("571df02ea99cff2c6826480b")
data := bson.M{"$set": bson.M{"key": "max", "value": 30}}
changeInfo, err := getDB().C("config").UpsertId(id, data)
if err != nil {
    panic(err)
}
fmt.Printf("%+v\n", changeInfo)
// 首次执行output: &{Updated:0 Removed:0 UpsertedId:ObjectIdHex("571df02ea99cff2c6826480b")}
// 再次执行output: &{Updated:1 Removed:0 UpsertedId:<nil>}

原文地址:https://www.cnblogs.com/williamjie/p/9692660.html

时间: 2024-07-31 09:39:50

Golang 中操作 Mongo Update 的方法的相关文章

Flex中操作XML的E4X方法

用于处理 XML 的 E4X 方法 Flash Player 9 和更高版本,Adobe AIR 1.0 和更高版本 ECMAScript for XML 规范定义了一组用于使用 XML 数据的类和功能.这些类和功能统称为 E4X.ActionScript 3.0 包含以下 E4X 类:XML.XMLList.QName 和 Namespace. E4X 类的方法.属性和运算符旨在实现以下目标: 简单 - 在可能的情况下,使用 E4X 可以更容易地编写和理解用于使用 XML 数据的代码. 一致

关于js中操作数组的一些方法

1.锁定数组的长度(让数组的长度变成只读). var a = [1,2,3] //定义一个数组 Object.defineProperty(a,"length",{ writable:false }) //将a数组的长度属性设为只读 a.length = 0 //将a的长度改为0 console.log(a.length); //打印a数组的长度,还是3 2.Array.join()方法,返回一个字符串 var a = [1,2,3]; var b = a.join("&qu

golang中结构体的初始化方法(new方法)

自定义一个结构体 type Rect struct { x, y float64 width, height float64 } 初始化方法: rect1 := new(Rect) rect2 := &Rect{} rect3 := &Rect{0, 0, 100, 200} rect4 := &Rect{width:100, height:200} 注意这几个变量全部为指向Rect结构的指针(指针变量),因为使用了new()函数和&操作符.而如果使用方法 a := Rec

js中操作数组的一些方法

增 push   在数组的末尾添加一个或多个元素,并返回新的长度.  array.push(1,2,3.........) unshift  在数组的开头添加一个或多个元素,并返回新的长度. array.unshift(1,2,3......) splice 在制定位置添加一个活多个元素,splice(start,0,str)  start必选, 删 pop   删除并返回数组最后一个元素 shift  删除并返回数组第一个元素 splice  删除数组中的元素,然后返回被删除的项目  spli

js中操作数组的一些方法【转】

增 push   在数组的末尾添加一个或多个元素,并返回新的长度.  array.push(1,2,3.........) unshift  在数组的开头添加一个或多个元素,并返回新的长度. array.unshift(1,2,3......) splice 在制定位置添加一个活多个元素,splice(start,0,str)  start必选, 删 pop   删除并返回数组最后一个元素 shift  删除并返回数组第一个元素 splice  删除数组中的元素,然后返回被删除的项目  spli

Golang中的字节序列化操作

在写网络程序的时候,我们经常需要将结构体或者整数等数据类型序列化成二进制的buffer串.或者从一个buffer中解析出来一个结构体出来,最典型的就是在协议的header部分表征head length 或者body length在拼包和拆包的过程中,需要按照规定的整数类型进行解析,且涉及到大小端序的问题. 1.C中是怎么操作的 在C中我们最简单的方法是用memcpy来一个整形数或者结构体等其他类型复制到一块内存中,然后在强转回需要的类型.如:     // produce     int a =

Golang中Struct与DB中表字段通过反射自动映射 - sqlmapper

Golang中操作数据库已经有现成的库"database/sql"可以用,但是"database/sql"只提供了最基础的操作接口: 对数据库中一张表的增删改查等操作,必须手动编写sql string,这通常都是一个写死的字符串(Hard-Code), 并且需要手动维护sql中字段与Golang中的变量的映射关系,这扩展性很差,且非常容易出错. 通常情况下,我们期望Golang中存在一个Struct与DB中的一个Table建立一个映射关系(Mapper), 之后我们

Go_18: Golang 中三种读取文件发放性能对比

Golang 中读取文件大概有三种方法,分别为: 1. 通过原生态 io 包中的 read 方法进行读取 2. 通过 io/ioutil 包提供的 read 方法进行读取 3. 通过 bufio 包提供的 read 方法进行读取 下面通过代码来验证这三种方式的读取性能,并总结出我们平时应该使用的方案,以便我们可以写出最优代码: package main import ( "os" "io" "bufio" "io/ioutil"

Golang 中三种读取文件发放性能对比

Golang 中读取文件大概有三种方法,分别为: 1. 通过原生态 io 包中的 read 方法进行读取 2. 通过 io/ioutil 包提供的 read 方法进行读取 3. 通过 bufio 包提供的 read 方法进行读取 下面通过代码来验证这三种方式的读取性能,并总结出我们平时应该使用的方案,以便我们可以写出最优代码: package main import ( "os" "io" "bufio" "io/ioutil"