前面几篇对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一个更强大的功能,聚合操作。