mongo回顾(六: 增删改查)

前面几篇对Mongo的索引做了最基本的介绍,本篇来聊聊mongo的增删改查操作
由于被朋友吐槽可读性不好,那就用上md吧
1,find

find 是 MongoDB 中查询数据的基本指令,相当于 SQL 中的 SELECT

db.movies.find( { "year" : 1975 } ) //单条件查询
db.movies.find( { "year" : 1989, "title" : "Batman" } ) //多条件and查询
db.movies.find( { $and : [ {"title" : "Batman"}, { "category" : "action" }] } ) // and的另一种形式
db.movies.find( { $or: [{"year" : 1989}, {"title" : "Batman"}] } ) //多条件or查询
db.movies.find( { "title" : /^B/} ) //按正则表达式查找

SQL MQL
a = 1 AND b = 1 {a: 1, b: 1}或{$and: [{a: 1}, {b: 1}]}
a = 1 OR b = 1 {$or: [{a: 1}, {b: 1}]}
a IS NULL {a: {$exists: false}}
a IN (1, 2, 3) {a: {$in: [1, 2, 3]}}

查询逻辑运算符

  • $lt: 存在并小于
  • $lte: 存在并小于等于
  • $gt: 存在并大于
  • $gte: 存在并大于等于
  • $ne: 不存在或存在但不等于
  • $in: 存在并在指定数组中
  • $nin: 不存在或不在指定数组中
  • $or: 匹配两个或多个条件中的一个
  • $and: 匹配全部条件

使用 find 搜索子文档
find 支持使用“field.sub_field”的形式查询子文档。假设有一个文档:

db.fruit.insertOne({
    name: "apple",
    from: {
        country: "China",
        province: "Guangdon"
    }
})

db.fruit.find( { "from.country" : "China" } );可以查询到该结果

使用 find 搜索数组

db.fruit.insert([
    { "name" : "Apple", color: ["red", "green" ] },
    { "name" : "Mango", color: ["yellow", "green"] }
])

db.fruit.find({$or: [{color: "red"}, {color: "yellow"}]} )两条都可以查到

在数组中搜索子对象的多个字段时, $elemMatch与and的区别

The $elemMatch operator matches documents that contain an array field with at least one element that matches all the specified query criteria.
数组子文档至少包含一个完全匹配的

db.survey.insertMany( [
   { "_id": 1, "results": [ { "product": "abc", "score": 10 },
                            { "product": "xyz", "score": 5 } ] },
   { "_id": 2, "results": [ { "product": "abc", "score": 8 },
                            { "product": "xyz", "score": 7 } ] },
   { "_id": 3, "results": [ { "product": "abc", "score": 7 },
                            { "product": "xyz", "score": 8 } ] },
   { "_id": 4, "results": [ { "product": "abc", "score": 7 },
                            { "product": "def", "score": 8 } ] }
] )

其中

db.survey.find(
   { results: { $elemMatch: { product: "xyz", score: { $gte: 8 } } } }
)

只返回id为3的,子文档必须要有一个满足全部条件

db.survey.find(
  { "results.product" : "xyz", "results.score": { $gte: 8  }}
)

id:1,2,3都返回

db.survey.find(
   { "results": { $elemMatch: { product: { $ne: "xyz" } } } }
)

id:1,2,3,4都返回,因为没有一个子文档只有xyz

db.survey.find(
   { "results.product": { $ne: "xyz" } }
)

只返回id为4的

控制 find 返回的字段

find 可以指定只返回指定的字段;(0不返回,1返回)

  • _id字段必须明确指明不返回,否则默认返回;
  • 在 MongoDB 中我们称这为投影(projection);
  • db.movies.find({"category": "action"},{"_id":0, title:1});

remove

remove是 MongoDB 中查询数据的基本指令,相当于 SQL 中的 DELETE

  • remove 命令需要配合查询条件使用;
  • 匹配查询条件的的文档会被删除;
  • 指定一个空文档条件会删除所有文档;

db.testcol.remove( { a : 1 } ) // 删除a 等于1的记录
db.testcol.remove( { a : { $lt : 5 } } ) // 删除a 小于5的记录
db.testcol.remove( { } ) // 删除所有记录
db.testcol.remove() //报错

3,drop

drop 删除集合,相当于SQL删除表

  • 使用 db.<集合>.drop() 来删除一个集合
  • 集合中的全部文档都会被删除
  • 集合相关的索引也会被删除
    db.colToBeDropped.drop()

4,dropDatabase

使用 dropDatabase 删除数据库,相当于SQL删除数据库

  • 使用 db.dropDatabase() 来删除数据库
  • 数据库相应文件也会被删除,磁盘空间将被释放
    use tempDB
    db.dropDatabase()
    show collections // No collections
    show dbs // The db is gone

5,update

使用 update 更新文档

  • 使用 updateOne 表示无论条件匹配多少条记录,始终只更新第一条;
  • 使用 updateMany 表示条件匹配多少条就更新多少条;
  • updateOne/updateMany 方法要求更新条件部分必须具有以下之一,否则将报错:
$set/$unset(删除字段)、$push/$pushAll/$pop、$pull/$pullAll、$addToSet
db.student.update({"section" : "第4章"},{"$unset":{"name":""}})
If the field does not exist, then $unset does nothing

使用 update 更新数组

  • $ 充当占位符以更新与查询条件匹配的第一个元素,占位符:代表匹配条件的第一个元素
  • $[] 充当占位符以更新数组中与查询条件匹配的文档中的所有元素
  • $[< identifier>] 充当占位符以更新与查询条件匹配的文档的arrayFilters条件匹配的所有元素
  • $push: 增加一个对象到数组底部
  • $pushAll: 增加多个对象到数组底部
  • $pop: 从数组底部删除一个对象
  • $pull: 如果匹配指定的值,从数组中删除相应的对象
  • $pullAll: 如果匹配任意的值,从数据中删除相应的对象
  • $addToSet: 如果不存在则增加一个值到数组

addToSet操作于数组,若数组不存在该数据则添加,不保证添加后的顺序

若添加值是数组,则直接增加,需要数组添加到原数组中,可以配合$each使用

{ _id: 1, letters: ["a", "b"] }
db.test.update(
   { _id: 1 },
   { $addToSet: { letters: [ "c", "d" ] } }
)
结果:{ _id: 1, letters: [ "a", "b", [ "c", "d" ] ] }

{ _id: 1, letters: [ "c", "a", "b"] }
db.test.update(
   { _id: 1 },
   { $addToSet: { tags: { $each: [ "c", "d"] } } }
 )
结果:{ _id: 1, letters: [ "c", "a", "b", "d"] }

update方法的upsert和multi

mongodb中的update的形式是这样的:
db.collectionName.update(query, obj, upsert, multi);
upsert(默认为false):如果upsert=true,query找到了符合条件的行,则修改这些行; 没有找到,则追加一行符合query和obj的行
multi(默认为false):如果multi=true,则修改所有符合条件的行,否则只修改第一条符合条件的行。

db.books.update(
   { item: "ZZZ135" },   // Query parameter
   {                     // Replacement document
     item: "ZZZ135",
     stock: 5,
     tags: [ "database" ]
   },
   { upsert: true }      // Options
)

若是Query parameter操作没有匹配到,则新增一条数据

{
  "_id" : ObjectId("5da78973835b2f1c75347a83"),
  "item" : "ZZZ135",
  "stock" : 5,
  "tags" : [ "database" ]
}

upsert使用时要注意并发情况;高并发upsert的话,查询操作完成,但是还没insert,这时会同时insert多条相同的数据;官方提出的解决方案是加上唯一索引

$ 使用

db.collection.update(
   { <array>: value ... },// // Query parameter
   { <update operator>: { "<array>.$" : value } }
)

$ 不要配合 upsert一起使用,如果Query parameter没匹配到,会以<array>.$为名字新增一个字段;ps:我实践的话是直接报错了
与$unset运算符一起使用时,$运算符不会从数组中删除匹配的元素,而是将其设置为null。
查询使用否定运算符时($ne,$not或者$nin),$运算符会失效;否定部分在$elemMatch表达式内则不会出现这个问题

{
  _id: 5,
  grades: [
     { grade: 80, mean: 75, std: 8 },
     { grade: 85, mean: 90, std: 5 },
     { grade: 90, mean: 85, std: 3 }
  ]
}
db.students.updateOne(
   {
     _id: 5,
     grades: { $elemMatch: { grade: { $lte: 90 }, mean: { $gt: 80 } } }
   },
   { $set: { "grades.$.std" : 6 } }
)
更新id为5的grades数组中,第一个grade小于等于90,mean大于80的数据,std为6,结果为
{
  _id: 5,
  grades: [
    { grade: 80, mean: 75, std: 8 },
    { grade: 85, mean: 90, std: 6 },
    { grade: 90, mean: 85, std: 3 }
  ]
}

$[] 使用

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

$[] 配合 upsert一起使用,如果Query parameter没完全匹配到,会直接报错
$[]不配合muti的话,只会更新第一个配置数组中的全部数据

{ "_id" : 1, "grades" : [ 85, 82, 80 ] }
{ "_id" : 2, "grades" : [ 88, 90, 92 ] }
{ "_id" : 3, "grades" : [ 85, 100, 90 ] }
db.students.update(
   { },
   { $inc: { "grades.$[]": 10 } },
   { multi: true }
)
//将grades数据全部加10
{ "_id" : 1, "grades" : [ 95, 92, 90 ] }
{ "_id" : 2, "grades" : [ 98, 100, 102 ] }
{ "_id" : 3, "grades" : [ 95, 110, 100 ] }

$[<identifier>]使用

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

$[<identifier>]将update operator过滤功能放在了arrayFilters中
在<identifier>必须以小写字母开头,并且只包含字母数字字符。

{ "_id" : 1, "grades" : [ 95, 92, 90 ] }
{ "_id" : 2, "grades" : [ 98, 100, 102 ] }
{ "_id" : 3, "grades" : [ 95, 110, 100 ] }

db.students.update(
   { },
   { $set: { "grades.$[element]" : 100 } },
   { multi: true,
     arrayFilters: [ { "element": { $gte: 100 } } ]
   }
)

{ "_id" : 1, "grades" : [ 95, 92, 90 ] }
{ "_id" : 2, "grades" : [ 98, 100, 100 ] }
{ "_id" : 3, "grades" : [ 95, 100, 100 ] }

$[<identifier>]的功能很灵活,对于数组中嵌套数组也能精准匹配并对应更新字段,时候用与复杂的匹配
https://docs.mongodb.com/manual/reference/operator/update/positional-filtered/

总结: mongo对文档的增删改查操作还是蛮强大的,下一篇聊聊mongo一个更强大的功能,聚合操作。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • NoSQL-MongoDB运维技术 # NoSQL-MongoDB 运维 # 第一章:MySQL 到 MongoD...
    StandingBy_abc阅读 230评论 0 0
  • 核心概念 字符串:所有字段串必须使用UTF-8编码 数字:bson指定了三种数据类型:double,int,lon...
    渡边Hok阅读 677评论 0 1
  • https://blog.csdn.net/kuang_jia_ji/article/details/786671...
    指向远方的灯塔阅读 609评论 0 1
  • 先来一个常用的赋值和输出命令,熟悉一下。(操作前你需要打开并链接到服务器)在命令行中输入以下代码。 需要注意的是这...
    DDLH阅读 244评论 0 0
  • 1. 什么是MongoDB数据库? MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统...
    Treehl阅读 810评论 0 2