美文网首页MongoDB笔记
增删查改超详细介绍

增删查改超详细介绍

作者: 逃跑的肉丸 | 来源:发表于2020-12-11 10:11 被阅读0次

    前言

    从库至今数据库的作用其实最主要的就是存放数据,而对数据的操作也就是增删查改,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),否则会报错

    简书1.png

    更新

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

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

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

    删除

    删除其实也没有什么可说的,就是删除你查询到的行数据,虽然也提供了很多种方法,但是一般使用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(
      [ <operation 1>, <operation 2>, ... ],
      {
          writeConcern : <document>,
          ordered : <boolean>
      })
    

    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" }
    

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

    相关文章

      网友评论

        本文标题:增删查改超详细介绍

        本文链接:https://www.haomeiwen.com/subject/lytjgktx.html