目前项目大量使用了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...