MongoDB基础之文档DML操作

1 文档DML

主要讲解的是文档的创建,更新,删除等相关操作

1.1 定义

文档是一组键值(key-value)对(即 BSON)。MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,也是 MongoDB 非常突出的特点

下表列出了 RDBMS 与 MongoDB 对应的术语:

RDBMS MongoDB
数据库 数据库
表格 集合
文档
字段
表联合 嵌入文档
主键 主键 (MongoDB 提供了 key 为 _id )

需要注意的是:

  • 文档中的键/值对是有序的。
  • 文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
  • MongoDB区分类型和大小写。
  • MongoDB的文档不能有重复的键。
  • 文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。

文档键命名规范:

  • 键不能含有\0 (空字符)。这个字符用来表示键的结尾。
  • .$有特别的意义,只有在特定环境下才能使用。
  • 以下划线_开头的键是保留的(不是严格要求的)

1.2 插入文档

由于文档的数据结构和JSON基本一样。所有存储在集合中的数据都是 BSON 格式。BSON 是一种类似 JSON 的二进制形式的存储格式,是 Binary JSON 的简称。

MongoDB 使用 insert()save() 方法向集合中插入文档,语法如下:

db.COLLECTION_NAME.insert(document)
或
db.COLLECTION_NAME.insertOne(document) 
或
db.COLLECTION_NAME.insertMany(document) 
或
db.COLLECTION_NAME.save(document)
  • save():如果 _id 主键存在则更新数据,如果不存在就插入数据。该方法新版本中已废弃,可以使用 db.collection.insertOne()db.collection.replaceOne() 来代替。
    如果不指定 _id 字段 save() 方法类似于insert()方法。如果指定 _id 字段,则会更新该 _id 的数据
  • insert(): 若插入的数据主键已经存在,则会抛 org.springframework.dao.DuplicateKeyException异常,提示主键重复,不保存当前数据。3.2 版本之后新增了 db.collection.insertOne()db.collection.insertMany()
  • db.collection.insertOne() 用于向集合插入一个新文档
  • db.collection.insertMany() 用于向集合插入一个多个文档,语法格式如下:

插入语法格式:

db.collection.insertMany(
   [ <document 1> , <document 2>, ... ],
   {
      writeConcern: <document>,
      ordered: <boolean>
   }
)

参数说明:

  • document:要写入的文档。
  • writeConcern:写入策略,默认为 1,即要求确认写操作,0 是不要求。
  • ordered:指定是否按顺序写入,默认 true,按顺序写入。

实例
以下文档可以存储在 MongoDB 的 test数据库 的 col 集合中:

db.test.insert({title: 'MongoDB 教程', 
    description: 'MongoDB 是一个 Nosql 数据库',
    by: 'myself',
    url: 'http://www.test.com',
    tags: ['mongodb', 'database', 'NoSQL'],
    likes: 100
})

以上实例中 test是我们的集合名,如果该集合不在该数据库中, MongoDB 会自动创建该集合并插入文档。

我们也可以将数据定义为一个变量,如下所示:

document=({title: 'MongoDB 教程', 
    description: 'MongoDB 是一个 Nosql 数据库',
    by: 'myself',
    url: 'http://www.test.com',
    tags: ['mongodb', 'database', 'NoSQL'],
    likes: 100
});

执行后显示结果如下:

document=({title: 'MongoDB 教程', 
    description: 'MongoDB 是一个 Nosql 数据库',
    by: 'myself',
    url: 'http://www.test.com',
    tags: ['mongodb', 'database', 'NoSQL'],
    likes: 100
});

执行插入操作:

db.test.insert(document)
WriteResult({ "nInserted" : 1 })

1.3 更新文档

使用 update() save() 方法来更新集合中的文档。接下来让我们详细来看下两个函数的应用及其区别。

1.3.1 update() 方法

update() 方法用于更新已存在的文档。语法格式如下:

db.collection.update(
   <query>,
   <update>,
   {
     upsert: <boolean>,
     multi: <boolean>,
     writeConcern: <document>
   }
)

参数说明:

  • query : update的查询条件,类似sql update查询内where后面的。
  • update: update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的
  • upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNewtrue为插入,默认是false,不插入。
  • multi : 可选,mongodb默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
  • writeConcern :可选,抛出异常的级别。
    WriteConcern.NONE:没有异常抛出
    WriteConcern.NORMAL:仅抛出网络错误异常,没有服务器错误异常
    WriteConcern.SAFE:抛出网络错误异常、服务器错误异常;并等待服务器完成写操作。
    WriteConcern.MAJORITY: 抛出网络错误异常、服务器错误异常;并等待一个主服务器完成写操作。
    WriteConcern.FSYNC_SAFE: 抛出网络错误异常、服务器错误异常;写操作等待服务器将数据刷新到磁盘。
    WriteConcern.JOURNAL_SAFE:抛出网络错误异常、服务器错误异常;写操作等待服务器提交到磁盘的日志文件。
    WriteConcern.REPLICAS_SAFE:抛出网络错误异常、服务器错误异常;等待至少2台服务器完成写操作

接着我们通过 update() 方法来更新标题(title):

>db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })   # 输出信息

以上语句只会修改第一条发现的文档,如果你要修改多条相同的文档,则需要设置 multi 参数为 true

>db.col.update({'title':'MongoDB 教程'},{$set:{'title':'MongoDB'}},{multi:true})

附:

  • db.collection.updateOne():向指定集合更新单个文档
  • db.collection.updateMany():向指定集合更新多个文档
  • 只更新第一条记录:
    db.col.update( { "count" : { $gt : 1 } } , { $set : { "test2" : "OK"} } );
  • 全部更新:
    db.col.update( { "count" : { $gt : 3 } } , { $set : { "test2" : "OK"} },false,true );
  • 只添加第一条:
    db.col.update( { "count" : { $gt : 4 } } , { $set : { "test5" : "OK"} },true,false );
  • 全部添加进去:
    db.col.update( { "count" : { $gt : 5 } } , { $set : { "test5" : "OK"} },true,true );
  • 全部更新:
    db.col.update( { "count" : { $gt : 15 } } , { $inc : { "count" : 1} },false,true );
  • 只更新第一条记录:
    db.col.update( { "count" : { $gt : 10 } } , { $inc : { "count" : 1} },false,false );

1.3.2 save() 方法

save() 方法通过传入的文档来替换已有文档,_id 主键存在就更新,不存在就插入。语法格式如下:

db.collection.save(
   <document>,
   {
     writeConcern: <document>
   }
)

参数说明:

  • document : 文档数据。
  • writeConcern :可选,抛出异常的级别。
    实例
    以下实例中我们替换了_id56064f89ade2f21f36b03136 的文档数据:
db.col.save({
    "_id" : ObjectId("56064f89ade2f21f36b03136"),
    "title" : "MongoDB",
    "description" : "MongoDB 是一个 Nosql 数据库",
    "by" : "myself",
    "url" : "http://www.test.com",
    "tags" : [
            "mongodb",
            "NoSQL"
    ],
    "likes" : 110
})

1.3.3 原子操作命令

MongoDB原子操作常用命令,如:$set$unset$inc

  • $set
    用来指定一个键并更新键值,若键不存在并新增该字段
    { $set : { field : value } }
  • $unset
    指定key,用来删除一个键。值是多少都不影响。好像并非真的删除,只是把它置为null
    { $unset : { field : 1} }
  • $inc
    $inc可以对文档的某个值为数字型(只能为满足要求的数字)的键进行增减的操作。
    { $inc : { field : value } }
    db.test.update({hometown:"蒙古"},{$inc:{age:2}}) age字段自增2
  • $push
    数组末尾追加一个元素
    用法:{ $push : { field : value } },会把value追加到field里面去,field一定要是数组类型才行,如果field不存在,会新增一个数组类型加进去。
    db.test.update({hometown:"蒙古"},{$set:{list:[1,2,3,4,5]}}) 新增一个列表
    db.test.update({hometown:"蒙古"},{$push:{list:6}}) 追加元素
  • $pushAll
    $push,只是一次可以追加多个值到一个数组字段内。
    { $pushAll : { field : value_array } }
  • $pull
    从数组field内删除一个等于value值,如果有多个相同元素,会全都被删除
    db.test.update({hometown:"蒙古"},{$pull:{list:6}})
  • $addToSet
    增加一个值到数组内,而且只有当这个值不在数组内才增加。
  • $pop
    删除数组的第一个最后一个元素,值只能选1-1
  • $rename
    修改字段名称
    { $rename : { old_field_name : new_field_name } }
  • $bit
    位操作,integer类型
    {$bit : { field : {and : 5}}}

1.3.4 位置操作符

1.3.4.1 位置操作符$

位置操作符$,如果不知道数组中元素的位置,可以使用位置$操作符
位置$操作符充当更新文档查询中第一个匹配的占位符,即使用了multi:true也没用
$可以在不显示指定数组元素位置的情况下标识要更新的数组中的元素,$只是单个占位符
.$[].会更新数组内全部元素,可以多个。.$.只会更新符合查询条件的数组内的元素,有且只能有一个

先查询
t.find() 
 { "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC", "comments" : [ { "by" : "joe", "votes" : 3 }, { "by" : "jane", "votes" : 7 } ] }
更新 
t.update( {'comments.by':'joe'}, {$inc:{'comments.$.votes':1}}, false, true )
再查询 
t.find() 
{ "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC", "comments" : [ { "by" : "joe", "votes" : 4 }, { "by" : "jane", "votes" : 7 } ] }

1.3.4.2 位置操作符$[]

位置操作符$[],要更新数组中的所有元素
查询条件匹配的情况下,$[]会修改指定数组字段中的所有元素
因为$[]修改整个数组。所以无需在查询条件中指定数组
注:3.6版本后的新功能

语法格式如下:

db.collection.updateMany(
   { <query conditions> },
   { <update operator>: { "<array>.$[]" : value } }
)

案例:

插入
db.stu.insert({_id:1,grades:[80,85,90]})
db.stu.insert({_id:2,grades:[88,90,92]})
db.stu.insert({_id:3,grades:[85,100,90]})
更新:
db.stu.update({grades:85},{$set:{'grades.$[]':'修改'}},{multi:true})

1.3.4.3 位置操作符$[< identifier >]

会使用一个或多个数组作为过滤条件进行匹配
在monodb3.6版本后才可使用
过滤后的位置运算符$[<identifier>]标识与arrayFilters条件匹配的数组元素来进行更新操作。
位置$[identifier]运算符充当数组字段中arrayFilters中指定条件匹配的所有元素的占位符

语法:

db.collection.update(
{ <update operator>: { "<array>.$[<identifier>]" : value } },
{ arrayFilters: [ { <identifier>: <condition> } ] }
)
或者:
db.collection.update(
   { <query selector> },
   { <update operator>: { "array.$[<identifier>].field" : value } },
   { arrayFilters: [ { <identifier>: <condition> } } ] }
)

注意:在<identifier>必须以小写字母开头,并且只包含字母数字字符

1.3.4.4 $elemMatch()

位置操作符$能够更新第一个匹配的数组元素,但是通过$elemMatch()操作符匹配多个内嵌文档的查询条件
考虑如下的stu集合文档grades字段是一个嵌套字段的文档

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

如下语句会更新嵌套文档中的std值为6,条件是文档的主键是4,字段grades的嵌套文档字段grade字段值小于等于90mean字段值大于80

db.students.update(
   {
     _id: 4,
     grades: { $elemMatch: { grade: { $lte: 90 }, mean: { $gt: 80 } } }
   },
   { $set: { "grades.$.std" : 6 } }
)

1.4 MongoDB 删除文档

MongoDB remove() 函数是用来移除集合中的数据。
MongoDB 数据更新可以使用 update() 函数。在执行 remove() 函数前先执行 find() 命令来判断执行的条件是否正确

db.collection.remove(
   <query>,
   <justOne>
)

参数说明:

  • query :(可选)删除的文档的条件。
  • justOne : (可选)如果设为 true1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。

但是remove()方法已经过时了,现在官方推荐使用 deleteOne()deleteMany() 方法。

删除集合下全部文档:
db.test.deleteMany({})

删除 status 等于 A 的全部文档:
db.test.deleteMany({ status : "A" })

删除 status 等于 D 的一个文档:
db.test.deleteOne( { status: "D" } )
posted @ 2022-11-05 19:38  上善若泪  阅读(73)  评论(0编辑  收藏  举报