MongoDB学习(二):CRUD操作、条件运算、分页操作、排序

目录

查询

插入

更新

删除


假设使用test数据库的user集合,有三条测试数据

查询

函数原型:db.collection_name.find(query,projection)

collection_name即集合的名称,query是查询条件(相当于SQL中的where子句),projection是投影条件(相当于SQL中的select子句),后两者都是可以不写的:

> use test
switched to db test
> db.user.insert({"name":"zhangsan","sex":"man","age":20,"hobby":"programming"})
WriteResult({ "nInserted" : 1 })
> db.user.find()
{ "_id" : ObjectId("5c3eef6d7da85af675c7c107"), "name" : "zhangsan", "sex" : "man", "age" : 20, "hobby" : "programming" }
{ "_id" : ObjectId("5c3eefee7da85af675c7c108"), "name" : "lisi", "sex" : "woman", "age" : 16, "hobby" : "music" }
{ "_id" : ObjectId("5c3ef0037da85af675c7c109"), "name" : "wangwu", "sex" : "man", "age" : 18, "hobby" : "read book" }

可以看到,什么都不写就相当于 select * from user 

下面测试带条件的查询:

> db.user.find({name:"zhangsan"})
{ "_id" : ObjectId("5c3eef6d7da85af675c7c107"), "name" : "zhangsan", "sex" : "man", "age" : 20, "hobby" : "programming" }
> db.user.find({age:{$gt:17}})
{ "_id" : ObjectId("5c3eef6d7da85af675c7c107"), "name" : "zhangsan", "sex" : "man", "age" : 20, "hobby" : "programming" }
{ "_id" : ObjectId("5c3ef0037da85af675c7c109"), "name" : "wangwu", "sex" : "man", "age" : 18, "hobby" : "read book" }
> db.user.find({age:{$gt:17}},{name:1})
{ "_id" : ObjectId("5c3eef6d7da85af675c7c107"), "name" : "zhangsan" }
{ "_id" : ObjectId("5c3ef0037da85af675c7c109"), "name" : "wangwu" }

第一条语句相当于 select * from user where name="zhangsan",第二条相当于 select * from user where age>17

这里使用的文档结构比较简单,假如有嵌套文档,可以用"子文档名.子文档字段名"的形式来选择字段,多层嵌套依此类推

可以看到,查询条件中,key是不需要带上双引号的

$gt代表大于号,类似的运算符还有:

操作 格式
等于 {<key>:<value>}
小于 {<key>:{$lt:<value>}}
小于或等于 {<key>:{$lte:<value>}}
大于 {<key>:{$gt:<value>}}
大于或等于 {<key>:{$gte:<value>}}
不等于

{<key>:{$ne:<value>}}

条件非 {<key>:{$not:条件}
逻辑或 {$or:[{<key1>:<value1>},{<key2>:<value2>}]}
非或 {$nor:[{<key1>:<value1>},{<key2>:<value2>}]}
条件与 {$and:[条件1,条件2,…]}
存在 {<key>:{$exists:true/false}}
类型查询

{<key>:{$type:<type>}}

逻辑与就是多个查询条件并列,一个逻辑或的例子:

> db.user.find({$or:[{age:{$gt:18}},{sex:"man"}]})
{ "_id" : ObjectId("5c3eef6d7da85af675c7c107"), "name" : "zhangsan", "sex" : "man", "age" : 20, "hobby" : "programming" }
{ "_id" : ObjectId("5c3ef0037da85af675c7c109"), "name" : "wangwu", "sex" : "man", "age" : 18, "hobby" : "read book" }

相当于 select name from user where age>17 or sex="man"

类型查询顾名思义,就是不按照值,而是按类型进行查找,假设有个人,名字就是数字,那么:

> db.user.find({name:{$type:'number'}})
{ "_id" : ObjectId("5c3f22a87da85af675c7c10a"), "name" : 10 }

类型和其数值对应如下:

Number Alias
1 “double”
2 “string”
3 “object”
4 “array”
5 “binData”
7 “objectId”
8 “bool”
9 “date”
10 “null”
11 “regex”
13 “javascript”
15 “javascriptWithScope”
16 “int”
17 “timestamp”
18 “long”
-1 “minKey”
127 “maxKey”

number是广义数字类型

除此之外,还有范围查询操作符:

操作符 说明
$in 匹配以下文档:包含给定集合中至少一个元素
$all 匹配以下文档:包含给定集合中全部元素
$nin 匹配以下文档:不包含给定集合中任何元素

例子:

> db.user.find({hobby:{$in:["programming","music"]}})
{ "_id" : ObjectId("5c3eef6d7da85af675c7c107"), "name" : "zhangsan", "sex" : "man", "age" : 21, "hobby" : "programming" }
{ "_id" : ObjectId("5c3eefee7da85af675c7c108"), "name" : "lisi", "sex" : "woman", "age" : 16, "hobby" : "music" }
> db.user.find({hobby:{$all:["programming","music"]}})
> db.user.find({hobby:{$nin:["programming","music"]}})
{ "_id" : ObjectId("5c3ef0037da85af675c7c109"), "name" : "wangwu", "sex" : "man", "age" : 18, "hobby" : "read book" }
{ "_id" : ObjectId("5c3f1885cce0b679769390fa"), "name" : "lucy", "age" : 22, "hobby" : "movie", "sex" : "woman" }
{ "_id" : ObjectId("5c3f1bbfcce0b67976939109"), "name" : "tom", "age" : 2 }
{ "_id" : ObjectId("5c3f22a87da85af675c7c10a"), "name" : 10 }

以及数组查询操作符:

操作符 说明 用法
$elemMatch 匹配成员数组中包含某个元素的文档 {<key>:{$elemMatch:<value>}}
$size 匹配数组元素数相同的文档 {<key>:{$size:<number>}}

MongoDB还提供了一个非常强力的查询操作符:$where,它可以使用JavaScript函数来选择数据,使用this指针获取文档中的成员:

> db.user.find({$where:"function(){return this.age>=20}"})
{ "_id" : ObjectId("5c3eef6d7da85af675c7c107"), "name" : "zhangsan", "sex" : "man", "age" : 21, "hobby" : "programming" }
{ "_id" : ObjectId("5c3f1885cce0b679769390fa"), "name" : "lucy", "age" : 22, "hobby" : "movie", "sex" : "woman" }

像示例中这种简单的查询,简写形式也是完全等效的:

db.user.find({$where:"this.age>=20"})

第三条语句相当于 select name from user where age>17 ,"{name:1}"代表投影到name这个域

projection有inclusion和exclusion两种模式,但不能混用:

> db.user.find({age:{$gt:17}},{name:1})   //inclusion模式,仅包含指定域
{ "_id" : ObjectId("5c3eef6d7da85af675c7c107"), "name" : "zhangsan" }
{ "_id" : ObjectId("5c3ef0037da85af675c7c109"), "name" : "wangwu" }
> db.user.find({age:{$gt:17}},{name:0})   //exclusion模式,仅排除指定域
{ "_id" : ObjectId("5c3eef6d7da85af675c7c107"), "sex" : "man", "age" : 20, "hobby" : "programming" }
{ "_id" : ObjectId("5c3ef0037da85af675c7c109"), "sex" : "man", "age" : 18, "hobby" : "read book" }
> db.user.find({age:{$gt:17}},{name:1,age:0})   //混用两种模式,报错
Error: error: {
        "ok" : 0,
        "errmsg" : "Projection cannot have a mix of inclusion and exclusion.",
        "code" : 2,
        "codeName" : "BadValue"
}

可以看到,两种模式下,_id域都会出现在结果中,如果想隐藏该域,只能显式指定{_id:0}

MongoDB还提供了一个findOne函数,顾名思义,是仅仅返回一个结果:

> db.user.findOne({$or:[{age:{$gt:18}},{sex:"man"}]})
{
        "_id" : ObjectId("5c3eef6d7da85af675c7c107"),
        "name" : "zhangsan",
        "sex" : "man",
        "age" : 20,
        "hobby" : "programming"
}

并且返回的文档自动进行了格式化,更清晰,find().limit(1).pretty()效果相同:

> db.user.find({$or:[{age:{$gt:18}},{sex:"man"}]}).limit(1).pretty()
{
        "_id" : ObjectId("5c3eef6d7da85af675c7c107"),
        "name" : "zhangsan",
        "sex" : "man",
        "age" : 21,
        "hobby" : "programming"
}

类似pretty(),find()函数还有些增强函数:

  • limit(number):限定查询数量
  • skip(number):跳过查询结果的前number条
  • sort({key1:1/-1,key2:1/-1,…}):按照key1、key2进行排序,1代表升序,-1代表降序

结合limitskip可以实现分页,但仅适用小规模数据,因为skip是先查询,再一个个跳过,对于大规模数据,其性能很差,可以加个自增字段,结合$gt运算符和limit实现分页

查询的结果其实就是一个BSON数据,因此可以赋给一个对象,并对其操作:

> zhangsan = db.user.findOne({name:"zhangsan"})
{
        "_id" : ObjectId("5c3eef6d7da85af675c7c107"),
        "name" : "zhangsan",
        "sex" : "man",
        "age" : 21,
        "hobby" : "programming"
}
> zhangsan['age']=22
22
> zhangsan
{
        "_id" : ObjectId("5c3eef6d7da85af675c7c107"),
        "name" : "zhangsan",
        "sex" : "man",
        "age" : 22,
        "hobby" : "programming"
}

这种数据替换不会对原始数据产生影响

插入

在 MongoDB学习(一):安装&基础概念&数据类型&部分shell操作 最后提到了插入方法,不再重复

更新

函数原型:db.collection_name.update(query,update,options)

collection_name和query的含义同find方法一样,update相当于SQL中的set子句,options有三种:

  • upsert : 可选,这个参数的意思是,如果要更新的文档不存在,是否插入新文档,true为插入,默认是false不插入。
  • multi : 可选,默认false,代表只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条所有记录全部更新。
  • writeConcern :可选,抛出异常的级别。形式为:writeConcern :{ w: <value>, j: <boolean>, wtimeout: <number> },用在分布式环境下
    • w:代表更新结果返回前,在集群中需要有多少台机器确认结果
      • w:0代表不需要确认

      • w:1代表只要主节点确认

      • w:2代表主节点和至少一个从节点确认,w=3、4、…… 依此类推

      • w:"majority"代表需要过半成员确认

      • w:{tag1,tag2……}代表需要指定tag的分片确认

    • j:代表是否需要写入journal文件

    • wtimeout:代表确认结果操作的超时时间

举个例子:

> db.user.update({name:"zhangsan"},{$set:{age:21}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find({name:"zhangsan"})
{ "_id" : ObjectId("5c3eef6d7da85af675c7c107"), "name" : "zhangsan", "sex" : "man", "age" : 21, "hobby" : "programming" }
> db.user.update({name:"tom"},{$set:{age:22,sex:"man",hobby:"pc games"}},{upsert:true})
WriteResult({
        "nMatched" : 0,
        "nUpserted" : 1,
        "nModified" : 0,
        "_id" : ObjectId("5c3f1885cce0b679769390fa")
})
> db.user.find({name:"tom"})
{ "_id" : ObjectId("5c3f1885cce0b679769390fa"), "name" : "tom", "age" : 22, "hobby" : "pc games", "sex" : "man" }

这里update部分使用的是$set操作符,其它操作符还有:

  • $set:{field:value} 更新指定键的值为value
  • $unset:{field:1} 删除指定键
  • $inc:{field:value} 对field的值增加value(仅限数字类型)
  • $push:{field:value} 向数组field添加一个元素value
  • $pushAll:{field:array} 将array中所有元素都添加到field中
  • $pull:{field:_value} 从数组field中删除一个值为value的元素(注意下划线)
  • $addToSet:{field:value} 增加一个值value到集合field内。
  • { $pop : { field : 1/-1 } } 删除数组第一个/最后一个元素
  • { $rename : { old_field_name : new_field_name } } 修改域的key
  • {$bit : { field : {bit_operator : number}}} 位操作
  • 偏移操作符:{'comments.by':'joe'}, {$inc:{'comments.$.votes':1}} 相当于对comments数组中,所有字段"by"为"joe"的子文档的"votes"字段+1

例如inc操作:

> db.user.update({name:"tom"},{$inc:{age:2}})
WriteResult({
        "nMatched" : 0,
        "nUpserted" : 1,
        "nModified" : 0,
        "_id" : ObjectId("5c3f1885cce0b679769390fa")
})
> db.user.find({name:"tom"})
{ "_id" : ObjectId("5c3f1885cce0b679769390fa"), "name" : "tom", "age" : 24, "hobby" : "pc games", "sex" : "man" }

tom的年龄大了两岁

可以看到,使用upsert选项后,文档不存在时会插入新文档

insert类似,update也有updateOneupdateMany两个变体

还有两个作用类似的函数:

  • db.collection_name.save(document,{writeConcern:{w:<value>,j:<boolean>,wtimeout:<number>}})

会根据主键进行文档替换:

> db.user.save({ "_id" : ObjectId("5c3f1885cce0b679769390fa"), "name" : "lucy", "age" : 22, "hobby" : "movie", "sex" : "woman" })
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find({name:"lucy"})
{ "_id" : ObjectId("5c3f1885cce0b679769390fa"), "name" : "lucy", "age" : 22, "hobby" : "movie", "sex" : "woman" }

可以看到,tom已经变成lucy了

  • db.collection_name.findAndModify(query,update) 是原子性操作,即这个函数要么完成,要么不生效
    • 注意:由于该函数不存在options参数,因此是默认upsert的,即如果没找到要修改的文档,就会插入新的

删除

函数原型:db.collection_name.remove(query,options)

重复的不解释了,options有两个:

  • justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配的文档。
  • writeConcern :和update的同名选项作用一致

和其它函数不同的是,其变体名字叫deleteOnedeleteMany

猜你喜欢

转载自blog.csdn.net/u010670411/article/details/86510467