mongodb学习笔记

目前项目大量使用了mongodb,之前一直没有很好地系统学习和总结这块知识,最近打算整理项目中遇到的一些知识点,以便温习

易出错的操作

mongo语句练习借鉴自:https://segmentfault.com/a/11...

  • 查看一年级二班的学生,年龄值有哪些
db.getCollection('grade_1_2').distinct('age')
  • 查看一年级二班的学生,男生(`sex`为 0)年龄值有哪些
db.getCollection('grade_1_2').distinct('age', {"sex": 0})
  • 查询结果中只显示某个字段
//只输出id和title字段,第一个参数为查询条件,空代表查询所有
db.news.find( {}, { id: 1, title: 1 } )

如果需要输出的字段比较多,不想要某个字段,可以用排除字段的方法

//不输出内容字段,其它字段都输出
db.news.find( {}, {content: 0 } )
  • 一年级二班`grade_1_2`中,修改名为`zhangsan1`的学生,年龄为 8 岁,兴趣爱好为 跳舞和画画;
db.getCollection('grade_1_2').update({"name": "zhangsan1"}, {$set: {"age": 8, "hobby": ["dance", "drawing"]}})
  • 一年级二班`grade_1_2`中,追加`zhangsan1`学生兴趣爱好吹牛和打篮球;
db.getCollection('grade_1_2').update({"name": "zhangsan1"}, {$push: {"hobby": {$each: ["brag", "play_basketball"]}}})
  • 新学年,给一年级二班所有学生的年龄都增加一岁
db.getCollection('grade_1_2').update({}, {$inc: {"age": 1}}, {multi: true})
  • 一年级二班`grade_1_2`中,删除`zhangsan1`学生的sex属性
db.getCollection('grade_1_2').update({"name": "zhangsan1"}, {$unset: {"sex": 1}})

注意unset只认key,value可以是任意的

  • 一年级二班`grade_1_2`中,删除`zhangsan1`学生的hobby数组中的头元素
db.getCollection('grade_1_2').update({"name": "zhangsan1"}, {$pop: {"hobby": -1}})
  • 一年级二班`grade_1_2`中,删除`zhangsan1`学生的`hobby`数组中的尾元素
db.getCollection('grade_1_2').update({"name": "zhangsan1"}, {$pop: {"hobby": 1}})
  • 一年级二班`grade_1_2`中,删除`zhangsan1`学生的`hobby`数组中的`sing`元素
db.getCollection('grade_1_2').update({"name": "zhangsan1"}, {$pull: {"hobby": "sing"}})
  • 查看一年级二班grade_1_2中所有年龄小于 4 岁并且大于 7 岁的学生
db.getCollection('grade_1_2').find({$or: [{"age": {$lt: 4}}, {"age": {$gt: 6}}]})
  • 查看一年级二班grade_1_2中所有兴趣爱好有三项的学生
db.getCollection('grade_1_2').find({"hobby": {$size: 3}})
  • 一年级二班`grade_1_2,给`zhangsan1`兴趣爱好添加跳舞
db.grade_1_3.update({name:"zhangsan1"},{$push:{hobby:"drawing"}})
  • 一年级二班`grade_1_2,给`zhangsan1`兴趣爱好添加跳舞,不能重复
db.grade_1_3.update({name:"zhangsan1"},{$addToSet:{hobby:"drawing"}})
  • $all为匹配数组中所有条件
db.users.find({age :  {$all :  [6,  8]}});

可以查询出:

{name:  'David', age:  26, age:  [  6,  8,  9  ]  }

但查询不出:

{name:  'David', age:  26, age:  [  6,  7,  9  ]  }
  • 查询出包含1或者包含4的数据
db.user.find({ id : { $in : ["1","4"] } } );

满足任一即可

findAndModify和update的比较

根据findAndModify的官方文档总结,主要有以下区别

  • 默认情况下,这两个操作都修改一个文档。但是,带有multi选项的update()方法可以修改多个匹配到query的文档。findAndModify没法修改多个文档;
  • 如果多个文档符合update条件,对于db.collection.findAndModify(),可以指定一个sort来提供对要更新的文档的某种控制措施。使用update()方法不能指定在多个文档匹配时更新哪个文档。
  • 默认情况下,db.collection.findAndModify()返回文档的预修改版本。要获取更新后的文档,请使用new选项。
  • update方法返回一个包含操作状态的WriteResult对象。
  • 当更新单个文档时,findAndModify和update方法都会原子性地更新文档(即先查询再更新是一个原子操作),

最重要的是,findAndModify和update都是原子操作,且findAndModify可以返回更新后的文档对象,update返回返回一个包含操作状态的WriteResult对象。

如何给内嵌文档更新值

假设我们的文档有个字段为coll,这个字段是一个object类型

{ "_id" : ObjectId("5e3cf2283737abd35ff5953d"), "name" : "jack", "age" : 18, "coll" : { "city" : "citizen", "city1" : "citizen" } }

我们想更新这个字段,为map里添加key,该怎么做呢?
可以用

db.market.update({name:"jack"},{$set:{"coll.school":"stu"}})

用coll."key"即可,不存在的话会追加写入,存在的话则覆盖

{ "_id" : ObjectId("5e3cf2283737abd35ff5953d"), "name" : "jack", "age" : 18, "coll" : { "city" : "citizen", "city1" : "citizen", "school" : "stu" } }

mgo操作mongo

当我们想更新name为jack1的数据,并将更新后的结果返回,可以按如下做法:

      var nj Jack
      demo := map[string]interface{}{
          "coll.p1": "1",
          "coll.p2": "2",
          "coll.p3": "3",
      }   
      updateMap := bson.M(demo)                                                                                                                          
      _, err = mgoHelper.GetColl().Find(bson.M{"name": "jack1"}).Apply(
          mgo.Change{
              Update:    bson.M{"$set": updateMap},
              ReturnNew: true,
          }, &nj)

这样没有问题,但如果我们定义

var nj *Jack
...
_, err = mgoHelper.GetColl().Find(bson.M{"name":"jack1"}).Apply(
          mgo.Change{
              Update:    bson.M{"$set": updateMap},
              ReturnNew: true,
         }, nj)

这样会报panic

reflect: call of reflect.Value.Type on zero Value

可以看mgo这个Apply方法的源码,发现

func (q *Query) Apply(change Change, result interface{}) (info *ChangeInfo, err error) {
    ...
    if doc.Value.Kind != 0x0A && result != nil {             
        err = doc.Value.Unmarshal(result)
        if err != nil {
            return nil, err
        }    
    }
    ...
}

result为nil时,直接会抛出err
这就要说到golang的一些基础知识,
第一种方式,var nj Jack,这样会生成{Name: Age:0 Coll:map[]},各个属性会设成其对应类型的零值,之后取&nj,则为&{Name: Age:0 Coll:map[]},不是nil
第二种方式,var nj *Jack,这样会直接初始化一个nil指针,因此报错了

参考文章

https://docs.mongodb.com/manu...
https://docs.mongodb.com/manu...
https://segmentfault.com/a/11...

你可能感兴趣的:(mongodb)