绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
增删查改超详细介绍
2019-07-27 17:11:30

增删查改超详细介绍

前言

从库至今数据库的作用其实主要的就是存放数据,而对数据的操作也就是增删查改,MongoDB也一样,虽然其有自己的一套操作语法,但是根本思想还是与SQL一样,只是可能没有SQL那么健壮,但是大部分的业务需求还是能够满足的,如果真不能满足我相信你也就不会选择MongoDB作为你的存储媒介了。

好,闲言碎语不要讲,我们开始学习如何对MongoDB里的数据进行操作

1.插入

1.1 表有如下两种方式创建:

db.tb1.insert({_id:1,name:"Kobe"})           //隐式创建,insert时自动创建新表
db.createCollection("tb1")                         //显式创建,创建一个空表

隐式创建没什么好说的,主要说两句 createCollection ,当你执行此命令后,会在数据文件目录下创建一个.wt的数据文件,伴随着也会有一个索引文件存在(_id主键索引树文件)默认4096bytes;


> db.createCollection("tb2")
$ ls -l
-rw------- 1 mongo mongo  4096 Jul 27 10:14 0-1144972512418703480.wt

也可以通过如下命令格式创建capped collection(固定集合)


db.createCollection("cap", { capped : true, size : 5242880, max : 5000 } )

1.2 插入数据提供了多种方法:
  • insertOne() 插入单一文档
  • insertMany() 插入多个文档,返回的是插入文档的ObjectID
  • insert() 插入单一或多个文档
    其实虽然提供了很多种方法,但是主要用insert()就够了
    
    > db.tb1.insert({ "_id" : 1, "x" : 1, "j" : 1 })    //普通插入
    WriteResult({ "nInserted" : 1 })        //返回结果,nInserted表示插入的文档数量
    > db.tb1.insert([                          //以数组的形式插入多个document
    ... { "_id" : 2, "x" : 4, "j" : 2 },
    ... { "_id" : 3, "x" : 2, "j" : 3 }
    ... ])
    BulkWriteResult({
      "writeErrors" : [ ],
      "writeConcernErrors" : [ ],
      "nInserted" : 2,    //结果返回的时插入成功的行数
      "nUpserted" : 0,
      "nMatched" : 0,
      "nModified" : 0,
      "nRemoved" : 0,
      "upserted" : [ ]
    })
    
    
    虽然insert和insertMany都能一次插入多条document记录,但是返回结果不一样,不信你看
    
    > db.tb1.insertMany([
    ... { "_id" : 4, "x" : 4, "j" : 4 },
    ... { "_id" : 5, "x" : 3 }
    ... ])
    { "acknowledged" : true, "insertedIds" : [ 4, 5 ] }   //结果返回的时插入行的id
    
    
    注: 上述通过的方法虽然都能将数据插入,但是返回结果有所不同,所以在做开发时请注意查看对应的API方法,使用正确的调用方法。
    1.3 基于表插入
    就是从其他表中查询的数据插入表中,类似SQL: insert into tb2 select * from tb1
    
    >db.tb1.find({_id:1}).forEach(
      function(myDoc)
          { var a=myDoc;
            db.tb2.insert(a);
             }
      )
    >db.tb2.find()
    { "_id" : 1, "x" : 1, "j" : 1 }
    
    
    1.4 批量插入测试数据
    
    > for(var i=1;i<10;i++) db.tb2.insert({userid:i,name:"johnny"});
    
    

    2 查询

    语法结构:
    
    db.collection.find( {query filter}, {projection} )
    //query filter: 个大括号{ }, 指定查询条件
    //projection: 第二个大括号{ },指定哪些字段需显示,从而限制结果集的输出大小
    
    
    基于上面创建的tb1集合进行条件查询
    
    > db.tb1.find()  //直接查询,类似select * from tb,类似于select * from tb1 order by j desc;
    > db.tb1.find().sort({j:-1})   //根据字段j排序,"1"表示升序,“-1”表示降序,类似于select * from tb1 order by j desc;
    > db.tb1.find({j:{$gt:2,$lte:4}})   //查询j<4 and j>2的记录,类似select * from tb1 where j<4 and j>2;
    $gt:大于
    $lt:小于
    $gte:大于等于
    $lte:小于等于
    $ne:不等于
    > db.tb1.find({j:{$in:[1,4]}})   //查询包含j=1或j=4的记录,类似select * from tb1 where j in (1,4); 不包括的话可以用$nin
    { "_id" : 1, "x" : 1, "j" : 1 }
    { "_id" : 4, "x" : 4, "j" : 4 }
    > db.tb1.find({x:2,j:{$gt:1}})   //查询x=1 and j>1条件记录,类似select * from tb1 where x=1 and j>1;
    >db.tb1.find({$or:[{x:4},{j:{$lte:2}}]})   //查询x=4 or j<=2的条件记录
    >db.tb1.find({x:1,$or:[{j:{$lt:2}},{j:3}]})   //查询x=1 and (j<2 or j=3)
    > db.tb1.find({x:1},{j:1})   //类似select j, _id from tb1 where x=1; 默认显示主键
    { "_id" : 1, "j" : 1 }
    > db.tb1.find({x:1},{j:1,_id:0})   //只返回某一字段
    { "j" : 1 }
    
    
    注: 在生产上查询数据时,好只返回需要的字段,不要使用类似select * 的方式
    不存在行的查询
    
    > db.tb1.insert({_id:6,x:6,j:null});   //插入j:null的行记录
    > db.tb1.find({j:{$exists:false}})   //查询不存在j字段的行,相反就是$exists:true
    { "_id" : 5, "x" : 3 }
    > db.tb1.find({j:null})   //不存在列也被查询到,是因为这样的查询方式会返回name=null且不存在name字段的记录
    { "_id" : 5, "x" : 3 }
    { "_id" : 6, "x" : 6, "j" : null }
    > db.tb1.find({j:{$type:10}})   //可以使用$type,10其实就代表了null这个数据类型
    { "_id" : 6, "x" : 6, "j" : null }
    
    
    常用type类型列表如下:
Type Number Alias
Double 1 “double”
String 2 “string”
Object 3 “object”
Array 4 “array”
Binary data 5 “binData”
ObjectId 7 “objectId”
Boolean 8 “bool”
Date 9 “date”
Null 10 “null”
Timestamp 17 “timestamp”

注: 更多type类型请参考 type类型
数组查询


> db.tb2.insertMany([   //插入测试数据
... { "_id" : 1, "userId" : 2, "Course" : [ "English", "Math" ], "finished" : [ 1, 26 ],info:{city:"TJ",age:22}},
... { "_id" : 2, "userId" : 3, "Course" : [ "Math", "English" ], "finished" : [ 18, 12 ],info:{city:"BJ",age:33}}
... ])
> db.tb2.find({Course:"English"})   //查询数组Course中包含元素“English”的行记录
{ "_id" : 1, "userId" : 2, "Course" : [ "English", "Math" ], "finished" : [ 1, 26 ], "info" : { "city" : "TJ", "age" : 22 } }
{ "_id" : 2, "userId" : 3, "Course" : [ "Math", "English" ], "finished" : [ 18, 12 ], "info" : { "city" : "BJ", "age" : 33 } }
> db.tb2.find({Course:["Math","English"]})   //只会查询到一行,而另外一笔数据虽然包含的元素一样,但是元素顺序不一致
{ "_id" : 2, "userId" : 3, "Course" : [ "Math", "English" ], "finished" : [ 18, 12 ], "info" : { "city" : "BJ", "age" : 33 } }
> db.tb2.find({Course:{$all:["English","Math"]}})   //只需包含指定元素,不关心元素的顺序位置
{ "_id" : 1, "userId" : 2, "Course" : [ "English", "Math" ], "finished" : [ 1, 26 ], "info" : { "city" : "TJ", "age" : 22 } }
{ "_id" : 2, "userId" : 3, "Course" : [ "Math", "English" ], "finished" : [ 18, 12 ], "info" : { "city" : "BJ", "age" : 33 } }
> db.tb2.find({"Course.1":"English"})   //查询数组中第2个元素是“English”的行记录,以为数组的下标从0开始
{ "_id" : 2, "userId" : 3, "Course" : [ "Math", "English" ], "finished" : [ 18, 12 ], "info" : { "city" : "BJ", "age" : 33 } }
 > db.tb2.find({finished:{$elemMatch:{$gt:15,$lt:20}}})   //需要数组中至少有一个元素满足所有条件
{ "_id" : 2, "userId" : 3, "Course" : [ "Math", "English" ], "finished" : [ 18, 12 ], "info" : { "city" : "BJ", "age" : 33 } }
> db.tb2.find({finished:{$gt:25,$lt:20}})   //数组中各个元素只满足一部分筛选条件,但是组合起来可以满足所有条件,则显示
{ "_id" : 1, "userId" : 2, "Course" : [ "English", "Math" ], "finished" : [ 1, 26 ], "info" : { "city" : "TJ", "age" : 22 } }
> db.tb2.find({Course:{$size:2}})   //根据数组中元素个数查询
{ "_id" : 1, "userId" : 2, "Course" : [ "English", "Math" ], "finished" : [ 1, 26 ], "info" : { "city" : "TJ", "age" : 22 } }
{ "_id" : 2, "userId" : 3, "Course" : [ "Math", "English" ], "finished" : [ 18, 12 ], "info" : { "city" : "BJ", "age" : 33 } }
> db.tb2.find({_id:2},{_id:0,finished:0,info:0,Course:{$slice:-1}})   //根据查询条件,返回数组Course中后一个元素
{ "userId" : 3, "Course" : [ "English" ] }

获取数组字段的数组长度


> db.tb2.find({_id:1}).forEach(function(x){
... var course=x.Course;
... print(course.length);
... })
2       //返回结果是2

嵌套子文档查询


> db.tb2.find({info:{city:"TJ",age:22}})   //根据子文档中的字段进行查询
或
>db.tb2.find({"info.city":"TJ","info.age":22})
> db.tb2.find({_id:1},{"info.city":1})   //返回子文档中的某个字段
{ "_id" : 1, "info" : { "city" : "TJ" } }

正则表达式


>db.tb3.insertMany([
{ "_id" : 1, "name" : "Jack", "addr" : "tianjin" },
{ "_id" : 2, "name" : "Tom", "addr" : "beijing" },
{ "_id" : 3, "name" : "Nick J" }
])
> db.tb3.find({name:/^J/})                //查询以J开头的记录
{ "_id" : 1, "name" : "Jack", "addr" : "tianjin" }
> db.tb3.find({name:{$not:/^J/}})          //查询不以J开头的记录
{ "_id" : 2, "name" : "Tom", "addr" : "beijing" }
{ "_id" : 3, "name" : "Nick J" }
> db.tb3.find({name:/J/})                    //查询name重包含J的记录
{ "_id" : 1, "name" : "Jack", "addr" : "tianjin" }
{ "_id" : 3, "name" : "Nick J" }

迭代查询
find()查询之后返回的是一个cursor游标,在mongo shell默认情况下迭代20次以显示前20个文档记录,如果使用变量的话:


> var a=db.tb3.find()
> while(a.hasNext()){
     printjson(a.next());
     }
{ "_id" : 1, "name" : "Jack", "addr" : "tianjin" }
{ "_id" : 2, "name" : "Tom", "addr" : "beijing" }
{ "_id" : 3, "name" : "Nick J" }
或者使用forEach( )
> var a=db.tb3.find()
> a.forEach(printjson)
{ "_id" : 1, "name" : "Jack", "addr" : "tianjin" }
{ "_id" : 2, "name" : "Tom", "addr" : "beijing" }
{ "_id" : 3, "name" : "Nick J" }
或者使用toArry( )逐一查询结果集
> var a=db.tb3.find()          ---定义变量
> var doc=a.toArray()          ---使用toArray( )生成数组结果集
> doc[0]                         ---查询结果集中个文档
{ "_id" : 1, "name" : "Jack", "addr" : "tianjin" }

去重查询


> db.tb3.distinct("name",{_id:{$gte:2}})
[ "Tom", "Nick J" ]

注: distinct返回的记录不能超过BSON文档大限制(16M),否则会报错

更新

更新其实也有很多种方法:

  • db.collection.updateOne() —-3.2版本的新功能,只更新匹配查询条件的document记录
  • db.collection.updateMany() —-3.2版本的新功能,更新匹配查询条件的所有document记录,其余功能和update()基本一致
  • db.collection.update()
  • db.collection.replaceOne() —-3.2版本的新功能,只更新替换匹配查询条件的个document记录,并且是替换整个
    默认情况是update只更新一条记录
    语法格式:

    
    db.collection.update(
    ,     //以{}形式填写查询条件,与find()方法一样
    ,     ---更新动作,默认是会用此区域的值覆盖原数据,仅更新某个字段请用$set,以设置字段的新值
    {
     upsert: ,     ---可选,当query的document不存在时,直接insert一个文档
     multi: ,     ---update()默认多只更新一条记录,multi:true可以多文档更新
     writeConcern:      ---一个完成返回模式,详细可查看官方文档
    })
    
    

    其实update也没什么好说的,在生产环境时小心使用即可;
    举例:

    
    > db.tb2.update({_id:1},{$set:{userId:11}});
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.tb2.update({_id:1},{$set:{name:"Kobe"}});   //name字段不存在时自动添加新字段
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    rs1:PRIMARY> db.tb2.find({_id:1})
    { "_id" : 1, "userId" : 11, "Course" : [ "English", "Math" ], "finished" : [ 1, 26 ], "info" : { "city" : "TJ", "age" : 22 }, "name" : "Kobe" }
    rs1:PRIMARY>
    
    

    重命名字段

    
    > db.tb2.update({},{$rename:{"userId":"u_id"}},{multi:true})
    WriteResult({ "nMatched" : 2, "nUpserted" : 0, "nModified" : 2 })
    > db.tb2.find()
    { "_id" : 1, "Course" : [ "English", "Math" ], "finished" : [ 1, 26 ], "info" : { "city" : "TJ", "age" : 22 }, "name" : "Kobe", "u_id" : 11 }
    { "_id" : 2, "Course" : [ "Math", "English" ], "finished" : [ 18, 12 ], "info" : { "city" : "BJ", "age" : 33 }, "u_id" : 3 }
    
    

    删除字段

    
    > db.tb2.update({},{$unset:{u_id:0}},{multi:true})  //u_id字段之后的值不重要,写多少都可以,依然可以删除此字段
    WriteResult({ "nMatched" : 2, "nUpserted" : 0, "nModified" : 2 })
    > db.tb2.find()
    { "_id" : 1, "Course" : [ "English", "Math" ], "finished" : [ 1, 26 ], "info" : { "city" : "TJ", "age" : 22 }, "name" : "Kobe" }
    { "_id" : 2, "Course" : [ "Math", "English" ], "finished" : [ 18, 12 ], "info" : { "city" : "BJ", "age" : 33 } }
    >
    
    

    注: 如果删除的字段或者嵌套文档在数组中,可考虑使用$pull
    判断性更新(存在即update,不存在则insert)

    
    > db.tb3.update({name:"Kobe"},{$set:{addr:"TJ"}},{upsert:true})   //upsert参数即实现此功能
    WriteResult({
     "nMatched" : 0,
     "nUpserted" : 1,
     "nModified" : 0,
     "_id" : ObjectId("5d3c0cfed33748cc8d4e0e67")
    })
    rs1:PRIMARY> db.tb3.find()
    { "_id" : 1, "name" : "Jack", "addr" : "tianjin" }
    { "_id" : 2, "name" : "Tom", "addr" : "beijing" }
    { "_id" : 3, "name" : "Nick J" }
    { "_id" : ObjectId("5d3c0cfed33748cc8d4e0e67"), "name" : "Kobe", "addr" : "TJ" }
    
    

    注: 此功能其实也可以使用save( ) 实现;
    数组更新

    
    >db.tb4.insert([
    { "_id" : 1, "age" : [ 3, 4, 5, 5, 9 ] }
    { "_id" : 2, "age" : [ 3, 5 ] }
    ])
    > db.tb4.update({age:5},{$set:{"age.$":55}})  //更新匹配到的个元素
    { "_id" : 1, "age" : [ 3, 4, 55, 5, 9 ] }
    { "_id" : 2, "age" : [ 3, 5 ] }
    
    

    更新数组中的嵌套子文档的字段值
    举例,如更新如下文档

    
    {
    _id: 4,
    grades: [
     { grade: 80, mean: 75, std: 8 },
     { grade: 85, mean: 90, std: 5 },
     { grade: 85, mean: 85, std: 8 }
    ]}
    
    

    更新语句如下:

    
    >db.tb5.updateOne(
    { _id: 4, "grades.grade": 85 },
    { $set: { "grades.$.std" : 6 } })
    
    

    数组中添加一个元素

    
    > db.tb4.update({_id:2},{$addToSet:{age:100}}) 
    WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
    > db.tb4.find()
    { "_id" : 1, "age" : [ 3, 4, 55, 5, 9 ] }
    { "_id" : 2, "age" : [ 3, 5, 100 ] }
    
    

    当然还有一个特殊方法findAndModify
    语法格式:

    
    db.collection.findAndModify({
     query: ,            //查询条件
     sort: ,                //对结果集排序
     remove: ,            //是否移除查询到的文档,只删除一个
     update: ,        //更新一条数据
     new: ,                //true后,返回修改后的文档内容
     fields: ,            //返回结果中显示哪些字段(列)
     upsert: ,            //true时,未匹配到则插入一条
     bypassDocumentValidation: ,    //绕过当前集合的文档约束
     writeConcern: ,            //强制写关注
     collation: ,                    //指定语言规则
     arrayFilters: [ , ... ]            //针对数组操作的参数设定
    });
    
    

    删除

    删除其实也没有什么可说的,就是删除你查询到的行数据,虽然也提供了很多种方法,但是一般使用remove就够了;

    
    > db.tb4.remove({_id:1})
    WriteResult({ "nRemoved" : 1 })
    >db.tb4.remove({})          ---传入空文档{ },则表示删除集合中的所有文档
    
    

    注: 虽然删除了集合上的所有文档记录,但索引定义还是存在的,不会随之而删除
    如果想要删除一个集合,好使用 drop( ) , 如db.tb4.drop( )

    批量操作

    上面讲了一堆增删改查的操作,不过都是单一英雄操作,如果我们想批量操作怎么办,那就拍一个《复仇者联盟》就好了呀——BulkWrite()
    官方的介绍是:MongoDB提供给客户端可以批量执行写操作的能力,不过只能影响一个collection
    BulkWrite()支持一下写操作:
    insertOne
    updateOne
    updateMany
    replaceOne
    deleteOne
    deleteMany
    语法格式:

    
    db.collection.bulkWrite(
    [ , , ... ],
    {
       writeConcern : ,
       ordered : 
    })
    
    

    operation1、operation2 都是一个个的写操作,以文档的形式放在[ ]数组中
    ordered :默认是true,即按照写操作的顺序执行,如果过程中某一操作报错,则剩余的操作将中断,false时,则是平行执行,一个操作的报错异常,不会影响到其余操作,但官方一般不建议,因为没有保证性
    实验:

    
    > db.t4.find()
    > db.t4.bulkWrite([
    ... {insertOne:{"document":{_id:1,a:1,name:"James"}}},
    ... {insertOne:{"document":{_id:2,a:2,name:"Johnny"}}},
    ... {updateOne:{"filter":{a:1},"update":{$set:{name:"Jack"}}}},
    ... {deleteOne:{"filter":{a:2}}}])
    {
         "acknowledged" : true,
         "deletedCount" : 1,
         "insertedCount" : 2,
         "matchedCount" : 1,
         "upsertedCount" : 0,
         "insertedIds" : {
                 "0" : 1,
                 "1" : 2
         },
         "upsertedIds" : {
         }
    }
    > db.t4.find()
    { "_id" : 1, "a" : 1, "name" : "Jack" }
    
    

    实验结果:
    插入一条、更新其中一条、删除其中一条

分享好友

分享这个小栈给你的朋友们,一起进步吧。

NoSQL与NewSQL
创建时间:2020-06-17 14:29:11
关注NoSQL与NewSQL,专区一站找到所需资料!
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

技术专家

查看更多
  • 小雨滴
    专家
戳我,来吐槽~