MongoDB—CRUD
mongodb Collection
命名规范
- 集合名第一个字符必须是字母
- 集合名不可以超过128个字符
- 集合名不可以包含 $ 符号,因为 $ 是 mongodb 中的系统保留字符
- 集合名不可以包含 空格
- 集合名不能以"system."开头,这是为系统集合保留的前缀
创建集合
直接插入文档
- mongodb 会自动创建集合
db.createCollection
https://docs.mongodb.com/v4.2/reference/method/db.createCollection/
- 创建一个新集合
- 一般用来创建具有特定选项的集合
格式
db.createCollection( <name>,
{
capped: <boolean>,
autoIndexId: <boolean>,
size: <number>,
max: <number>,
storageEngine: <document>,
validator: <document>,
validationLevel: <string>,
validationAction: <string>,
indexOptionDefaults: <document>,
viewOn: <string>, // Added in MongoDB 3.4
pipeline: <pipeline>, // Added in MongoDB 3.4
collation: <document>, // Added in MongoDB 3.4
writeConcern: <document>
}
)
-
name
- 类型:字符串
- 描述:要创建的集合名称
-
options
-
类型:document
-
描述:集合的相关配置
-
capped
- 类型:布尔
- 描述:
- true:创建一个固定大小的集合,必须结合 size 选项使用
-
autoIndexId
3.2版本之后弃用
从4.0版本开始,不能在 local 以外的数据库中设置此选项
官方不推荐使用!!!
- 类型:布尔
- 描述:
- false:不会自动将
_id
字段创建为索引
- false:不会自动将
-
size
- 类型:number
- 描述:
- 指定固定集合的大小(字节),必须结合 capped 使用
- 当固定集合超过设定的大小时,mongodb会删除旧文档为新文档腾出空间
-
max
- 类型:number
- 描述:
- 指定固定集合中可存放的最大文档数量
- 当固定集合中的文档数量超过设定的数量,mongodb会自动删除旧文档
- size 选项的优先级高于 max 选项,如果一个固定集合在达到最大文档数量之前达到的占用空间大小的限制,则mongodb依然会删除旧文档
- 要使用此选项应确保 size 选项足以包含文档的最大数量
-
storageEngine
-
类型:document
-
描述:
-
设定集合使用的存储引擎配置(仅对于 WiredTiger 存储引擎)
-
格式
{ <storage-engine-name>: <options> }
-
-
-
validator
- 类型:document
- 描述:
- 允许用户在创建集合时添加数据校验功能
-
validationLevel
-
类型:字符串
-
描述:确定MongoDB在更新过程中对现有文档应用验证规则的严格程度
-
"off"
关闭校验规则
-
"strict" 【默认】
对文档所有的更新和新增操作进行验证
-
"moderate"
['mɒdəreɪt] 适度的
仅对 已符合校验规则的 现有文档 进行新增和更改验证,对 不符合校验规则的 现有文档不再进行操作校验
-
-
-
validationAction
-
类型:字符串
-
描述:对于数据校验无效的文档的处理措施,仅适用于 validationLevel 确定的那些文档
-
"error"【默认】
如果新增或更新操作不符合校验规则,则mongodb自动报错
在发生写操作之前,文档必须通过校验,否则写操作失败
-
"warn"
如果新增或更新操作不符合校验规则,mongodb不会报错,但会把错误信息记录在日志中
-
-
-
indexOptionDefaults
- 类型:document
- 描述:设定索引使用的存储引擎配置
-
viewOn
- 类型:字符串
- 描述:指定用来创建视图的原集合或原视图名称
-
pipeline
- 类型:数组
- 描述:包含聚合管道阶段的数组
-
collation
- 类型:document
- 描述:指定集合的默认排序规则
-
writeConcern
- 类型:document
- 描述:指定集合的写入策略,如果忽略则使用默认写入策略
-
-
权限控制
具有 readWrite 内建角色的用户具有上述操作的所有权限,可将角色授予现有用户用来执行上述操作
示例
-
创建固定集合
db.createCollection("log", { capped : true, size : 5242880, max : 5000 } )
-
创建具有数据校验的集合
db.createCollection( "contacts", { validator: { $jsonSchema: { bsonType: "object", required: [ "phone" ], properties: { phone: { bsonType: "string", description: "must be a string and is required" }, email: { bsonType : "string", pattern : "@mongodb\.com$", description: "must be a string and match the regular expression pattern" }, status: { enum: [ "Unknown", "Incomplete" ], description: "can only be one of the enum values" } } } } } )
插入
db.contacts.insert( { name: "Amanda", status: "Updated" } )
报错
WriteResult({ "nInserted" : 0, "writeError" : { "code" : 121, "errmsg" : "Document failed validation" } })
删除集合
db.collection.drop
- 删除集合或视图,同时删除跟集合关联的索引
格式
db.collection.drop( { writeConcern: <document> } )
Returns
-
true
删除成功
-
false
集合不存在
查询集合
查询当前数据库中有哪些集合
show collections
show tables
重命名
db.collection.renameCollection
- 重命名集合
- 不支持分片集合和视图
格式
db.collection.renameCollection(target, dropTarget)
-
target
- 类型:字符串
- 描述:新名称
-
dropTarget
-
类型:布尔
-
描述:
-
true
如果新名称已经存在,则在重命名之前,删除已经存在的新名称集合
-
false【默认】
如果新名称已经存在,则重命名失败
"errmsg" : "target namespace exists"
-
-
示例
db.rrecord.renameCollection("record")
- 将 rrecord 重命名为 record
- 如果 record 集合已经存在,则操作失败
固定集合
capped collection
具有 固定大小的 存储空间的 集合
特点
-
基于文档的插入顺序存储于磁盘中
-
基于插入顺序的 插入和查询操作 具有很高性能
写入速度非常块
查询具有顺序的文档时,查询速度很快
-
工作机制类似循环缓存区,一旦集合填满了所分配的空间,就会自动删除最旧的文档,用来插入新文档
-
固定集合可以确保文档的插入顺序,因此不需要为插入顺序建立索引,可以支持非常高的插入吞吐量
在不指定顺序的查询操作中,mongodb 保证查询结果的顺序与插入顺序一致
-
默认情况下,固定集合有一个
_id
字段和建立在其之上的索引 -
存储空间的大小为 256 的整数倍,最小空间为 4096 字节
限制
-
与TTL索引不兼容
TTL 是固定集合的替代方案
-
不能更改文档大小
-
不能使用 delete 指令删除固定集合中的文档,只能使用 drop 指令删除集合再重新创建
-
固定集合不能分片
-
聚合管道阶段中的 $out 结果不能写入固定集合
-
从MongoDB 4.2开始,事务中的固定集合不支持写数据,但支持读取数据
创建
db.createCollection
- 创建新的固定集合
格式
db.createCollection( <name>, { capped:true, size: <number1>, max: <number2> } )
- capped:true
- size: <number1> 指定固定集合空间大小
- max:<number2> 指定固定集合中文档数量
db.runCommand
- 把当前集合转换为固定集合
- 执行过程中持有一个数据库独占锁,其他锁定同一数据库的操作将被阻塞,直到操作完成
格式
db.runCommand( "convertToCapped": <name>, size: <number1> )
- name 当前集合名
- size: <number1> 指定固定集合空间大小
检验
db.collection.isCapped
db.collection.isCapped()
返回结果
- true:是固定集合
- false,非固定集合
应用
-
存储由大容量系统生成的日志信息,在没有索引的情况下,使用固定集合插入文档的速度接近于将日志信息直接写入文件系统的速度
例如mongodb中的用来同步复制的 oplog 就是一个固定集合
-
缓存少量的数据
mongodb CRUD
create read update delete
Create
- collection 需要指定具体的集合名,如果集合不存在,则会创建
db.collection.insert
- 插入文档
格式
db.collection.insert(
<document or array of documents>,
{
writeConcern: <document>,
ordered: <boolean>
}
)
-
document or array of documents
- 插入一个或多个文档
- 插入一个文档,文档内容放在
{ }
中,如{ doc }
- 插入多个文档,单个文档内容放在
{ }
中,然后一起放在[ ]
中,如[ { doc1 }, { doc2 } ]
-
writeConcern
-
【可选】是否使用写入策略
-
ordered
- 【可选】默认为true
- 若为 true,表示有序插入,当有一个文档插入时发生错误,则后续文档不再继续插入
- 若为 false,表示无序插入,当有一个文档插入时发生错误,会继续执行后续文档的插入动作
insert 包含 insertOne 和 insertMany
示例
> db.person.insert([
... {
... name:"lfp",
... age:18,
... birth: new Date("1992-10-24")
... },
... {
... name:"xm",
... age:19,
... birth: new Date("1991-01-22")
... }
... ])
db.collection.insertOne
- 插入一个文档
格式
db.collection.insertOne(
<document>,
{
writeConcern: <document>
}
)
db.collection.insertMany
- 插入多个文档
格式
db.collection.insertMany(
[ <document 1> , <document 2>, ... ],
{
writeConcern: <document>,
ordered: <boolean>
}
)
db.collection.save
- 插入一个新的文档
- 更新一个已经存在的文档(需通过
_id
字段进行覆盖式更新) - 插入主键相同的文档时,insert 方法会报错,save 方法会覆盖原文档
格式
db.collection.save(
<document>,
{
writeConcern: <document>
}
)
新版本中有可能被废弃,建议使用 insertOne 或 replaceOne
4.2 版本测试仍可以使用
- document 需要保存的文档
- writeConcern
- 【可选】是否使用写入策略
示例
当插入_id
主键相同的文档时会覆盖
> db.person.save({
... _id:ObjectId("5f2d16c2cbb6771db2cf3db9"),
... name:"lfp",
... age:23,
... birth:new Date("1992-10-24")
... })
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
- 5f2d16c2cbb6771db2cf3db9 该id已经存在
- 覆盖原文档(删除原文档,使用新插入的文档)
Read/Query
query an array
-
查询数组元素中是否包含指定的元素,针对的是数组中的每一个元素
{ <array field>: { <operator1>: <value1>, ... } }
例如
db.inventory.find( { dim_cm: { $gt: 25 } } )
- 数组中的元素值大于25
db.collection.find
- 查询集合或视图中的文档并返回
格式
db.collection.find(
<query>,
<projection>
)
-
query【可选】
-
类型:document
-
描述
- 查询条件
- 通过查询操作符指定
- 忽略该选项或指定为空文档
{ }
,将返回集合中所有的文档
-
projection【可选】
-
类型:document =>
{ field1: <value>, field2: <value> ... }
-
字段值为1,表示显示此字段(include)
-
字段值为0,表示不显示此字段(exclude)
_id
字段默认显示,若不想显示则指定 -
不能同时包含 include 和 exclude 行为,除了
_id
字段 -
通过 Projection 操作符指定
在视图中查询时,不能使用 \(、\)eleMatch、\(slice、\)meta 操作符
-
-
描述
- 指定查询结果中需要显示的字段
- 如果忽略则显示文档中的所有字段
-
Returns
返回指向文档的游标
游标 cursor 指向符合查询条件的文档,find 方法实际返回的是指向文档的游标
示例
文档
-
返回集合中的所有文档
db.bios.find()
-
返回符合指定条件的文档
- 相等操作符
$eq
db.bios.find( { _id : 5 } ) db.bios.find( { "name.last" : "Hopper" } )
- 其他操作符
db.bios.find( { birth : { $gt : new Date('1992-01-01') } } ) // 正则 db.bios.find( { "name.last" : { $regex : /^N/ } } ) // 范围,一个子文档中用多个查询操作符表示范围 db.bios.find( { birth : { $gt: new Date('1940-01-01'), $lt: new Date('1960-01-01') } } ) // 多条件查询 db.bios.find( { birth : { $gt : new Date('1940-01-01') }, death : { $exist : false } } )
- 除了 $eq 可以省略,其他比较操作符都是一个子文档类型
- 相等操作符
db.collection.findOne
-
查询集合或视图中的文档,并返回符合条件的第一个文档
按照自然顺序,即磁盘上文档的顺序,在 capped 集合中,相当于插入顺序
-
如果没有符合条件的文档,则返回 null
格式
db.collection.find(
<query>,
<projection>
)
- query 和 projection 同 find
Returns
返回文档而非游标
示例
db.bios.findOne(
{
$or: [
{ 'name.first' : /^G/ },
{ birth: { $lt: new Date('01/01/1945') } }
]
}
)
- 查询条件是
- 嵌套文档name中的first字段以 G 开头 或
- birth 字段 小于 new Date('01/01/1945')
db.collection.findAndModify
db.collection.findOneAndDelete
db.collection.findOneAndReplace
db.collection.findOneAndUpdate
Update
- collection 需要指定具体的集合名
db.collection.update
- 更新文档
格式
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ],
hint: <document|string> // Available starting in MongoDB 4.2
}
)
-
query
-
类型:document
-
描述:
-
更新条件,符合更新条件的文档将被更新
-
使用与find()方法中相同的查询选择器
-
-
-
update
-
类型:document 或 pipeline
-
document
- 如果是更新文档,则文档内容是 操作表达式
- 如果是替换文档,则文档内容是 文档键值对
-
pipeline
4.2版本新增
聚合管道
-
-
描述:更新操作
-
-
options
-
upsert
-
类型:布尔【可选】
-
true
若没有匹配的文档,会插入当前文档
-
false 【默认】
若没有匹配的文档,则不插入当前文档
-
-
描述:
-
-
multi
-
类型:布尔【可选】
-
true
更新所有匹配的文档
-
false【默认】
只更新匹配到的第一个文档
-
-
writeConcern
- 类型:文档 ?
{ w:1 }
【默认】
- 描述:写入策略
- 类型:文档 ?
-
collation
- 类型:文档【可选】
- 为字符串指定特定于语言的排序规则
-
arrayFilters
-
类型:数组【可选,3.6新增】
-
一个标识符只能对应一个数组过滤器文档
// INVALID [ { "x.a": { $gt: 85 } }, { "x.b": { $gt: 80 } } ] // Example 1 [ { $or: [{"x.a": {$gt: 85}}, {"x.b": {$gt: 80}}] } ] // Example 2 [ { $and: [{"x.a": {$gt: 85}}, {"x.b": {$gt: 80}}] } ] // Example 3 [ { "x.a": { $gt: 85 }, "x.b": { $gt: 80 } } ]
-
当 更新文档 是对嵌套数组中的元素进行更改,则会出现两个标识符,此时会有两个数组过滤器文档
-
-
描述
-
数组元素的过滤条件,用来确定哪些元素被更新(数组过滤器)
-
当 update 类型是 document 时,使用
$[ < identifier > ]
来定义一个 标识符,代表元素下标,在 arrayFilters 中用 identifier 代表元素,设定元素的过滤条件$[ < identifier > ]
整体代表元素下标
都需要用引号包裹 '$' 'identifier' -
当 update 类型是 聚合管道时,不能使用 arrayFilters 选项
-
-
-
Returns
返回一个 WriteResult 文档,包含操作的状态
-
Successful Results
执行成功
-
nMatched
符合条件的文档数量
-
nUpserted
更新操作插入的文档数量
-
nModified
更新文档的数量
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
-
-
Write Concern Errors
执行时发生写入策略错误,需要用 try-catch 捕获
-
writeConcernError
写入策略错误对象
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1, "writeConcernError" : { "code" : 64, "errmsg" : "waiting for replication timed out at shard-a" } })
-
-
Errors Unrelated to Write Concern
执行时发生其他错误(非写入策略错误),需要用 try-catch 捕获
-
write Error
错误对象
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0, "writeError" : { "code" : 7, "errmsg" : "could not contact primary for replica set shard-a" } })
-
示例
-
数组过滤器
db.students.insertMany([ { "_id" : 1, "grades" : [ 95, 92, 90 ] }, { "_id" : 2, "grades" : [ 98, 100, 102 ] }, { "_id" : 3, "grades" : [ 95, 110, 100 ] } ])
更新
db.students.update( { grades: { $gte: 100 } }, { $set: { "grades.$[element]" : 100 } }, { multi: true, arrayFilters: [ { "element": { $gte: 100 } } ] } )
- 更新 grades 数组中某个元素值大于等于100的 文档
- 如果文档中的grades数组中的元素值大于等于100,则将其更改为100
db.collection.updateOne
- 只更新一个符合条件的文档
格式
db.collection.updateOne(
<filter>,
<update>,
{
upsert: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ],
hint: <document|string> // Available starting in MongoDB 4.2.1
}
)
-
filter
-
类型:document
-
描述:
-
选择条件,符合条件的文档将被更新
-
使用与find()方法中相同的查询选择器
-
如果指定一个空文档
{ }
,将更新集合中的第一个文档
-
-
-
writeConcern
- 类型:document
- 如果忽略则使用默认策略
- 描述:写入策略
- 类型:document
Returns
同 update 方法
示例
-
filter 为空文档
文档
db.members.insertMany([ { "_id" : 1, "name" : "Central Perk Cafe", "Borough" : "Manhattan" }, { "_id" : 2, "name" : "Rock A Feller Bar and Grill", "Borough" : "Queens", "violations" : 2 }, { "_id" : 3, "name" : "Empire State Pub", "Borough" : "Brooklyn", "violations" : 0 } ])
更新
db.members.updateOne( { }, { $set:{ "villations":4 }} )
- 只修改集合中第一个文档
db.collection.updateMany
- 更新所有符合条件的的文档
格式
db.collection.updateMany(
<filter>,
<update>,
{
upsert: <boolean>,
writeConcern: <document>,
collation: <document>,
arrayFilters: [ <filterdocument1>, ... ],
hint: <document|string> // Available starting in MongoDB 4.2.1
}
)
-
filter
-
类型:document
-
描述:
-
选择条件,符合条件的文档将被更新
-
使用与find()方法中相同的查询选择器
-
如果指定一个空文档
{ }
,将更新集合中的所有文档
-
-
-
writeConcern
- 类型:document
- 如果忽略则使用默认策略
- 描述:写入策略
- 类型:document
Returns
-
方法将返回一个文档,包含以下字段
-
acknowledged
-
类型:布尔
-
true
执行写入策略
-
false
写入策略被禁用
-
-
-
matchedCount
- 类型:number
- 描述:符合条件的文档数量
-
modifiedCount
- 类型:number
- 描述:被更新的文档数量
-
upsertedId
- 被更新文档的
_id
- 被更新文档的
-
示例
-
filter 为空,更新所有文档
文档
db.members.insertMany([ { "_id" : 1, "name" : "Central Perk Cafe", "Borough" : "Manhattan" }, { "_id" : 2, "name" : "Rock A Feller Bar and Grill", "Borough" : "Queens", "violations" : 2 }, { "_id" : 3, "name" : "Empire State Pub", "Borough" : "Brooklyn", "violations" : 0 } ])
更新
db.members.updateMany( { }, { $set:{ "age":27 }} )
- 所有文档都新增了 age 字段
db.collection.replaceOne
- 替换一个符合条件的文档
格式
db.collection.replaceOne(
<filter>,
<replacement>,
{
upsert: <boolean>,
writeConcern: <document>,
collation: <document>,
hint: <document|string> // Available starting in 4.2.1
}
)
-
filter
-
类型:document
-
描述:
-
选择条件,符合条件的文档将被替换
-
使用与find()方法中相同的查询选择器
-
如果指定一个空文档
{ }
,将替换集合中的第一个文档
-
-
-
replacement
- 类型:文档
- 描述:
- 替换文档
- 不能包含更新操作符
-
writeConcern
- 类型:文档
- 如果忽略则使用默认策略
- 描述:写入策略
- 类型:文档
Returns
同 updateMany
示例
-
使用 upsert
文档
db.members.insertMany([ { "_id" : 1, "name" : "Central Perk Cafe", "Borough" : "Manhattan", "violations" : 3 }, { "_id" : 2, "name" : "Rock A Feller Bar and Grill", "Borough" : "Queens", "violations" : 2 }, { "_id" : 3, "name" : "Empire State Pub", "Borough" : "Brooklyn", "violations" : 0 } ])
更新
try { db.members.replaceOne( { "name" : "Pizza Rat's Pizzaria" }, { "_id": 4, "name" : "Pizza Rat's Pizzaria", "Borough" : "Manhattan", "violations" : 8 }, { upsert: true } ); } catch (e){ print(e); }
- 因为使用了
upsert : true
选项,没有符合条件的文档时,则插入替换文档
- 因为使用了
Delete
db.collection.remove
- 删除符合条件的文档
格式
db.collection.remove(
<query>,
<justOne>
)
-
query
- 类型:document
- 描述
- 删除条件
- 通过查询操作符指定
- 如果指定一个空文档
{ }
,将删除集合中的所有文档
-
justOne【可选】
-
类型:布尔
-
true
仅删除符合条件的第一个文档
-
false【默认】
删除符合条件的所有文档
-
-
描述:是否仅删除第一个符合条件的文档
-
db.collection.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>,
collation: <document>
}
)
-
query
同上
-
justOne
同上
-
writeConcern
- 类型:document
- 如果忽略则使用默认写入策略
- 描述:写入策略
- 类型:document
Returns
返回一个 WriteResult 包含操作状态
-
Successful Results
执行成功
-
nRemoved
删除文档的数量
WriteResult({ "nRemoved" : 4 })
-
-
Write Concern Errors
执行时发生写入策略错误,需要用 try-catch 捕获
-
writeConcernError
写入策略错误对象
-
-
Errors Unrelated to Write Concern
执行时发生其他错误(非写入策略错误),需要用 try-catch 捕获
-
write Error
错误对象
-
示例
-
格式1,使用 justOne 选项
文档
db.myColl.insert([ { _id: 1, category: "café", status: "A" }, { _id: 2, category: "cafe", status: "a" }, { _id: 3, category: "cafE", status: "a" }, ])
删除
db.myColl.remove( {status:"a"}, true )
- 指定 justOne 为 true,只删除
_id
为2 的文档
- 指定 justOne 为 true,只删除
-
格式2,使用 justOne 选项
删除
db.myColl.remove( {status:"a"}, {justOne:true} )
- 使用 justOne 选项,只删除
_id
为2 的文档
- 使用 justOne 选项,只删除
-
删除集合中所有文档
删除
db.myColl.remove( {} )
db.collection.deleteOne
- 删除一个符合条件的文档
格式
db.collection.deleteOne(
<filter>,
{
writeConcern: <document>,
collation: <document>
}
)
- filter
- 类型:document
- 描述:
- 删除条件
- 通过操作符指定
- 如果指定一个空文档
{ }
,将删除集合中的第一个文档
Returns
返回一个文档,包含
-
acknowledged
-
类型:布尔
-
true
执行写入策略
-
false
写入策略被禁用
-
-
-
deletedCount
- 类型:number
- 描述:删除文档的数量
db.collection.deleteMany
- 删除所有符合条件的文档
格式
db.collection.deleteMany(
<filter>,
{
writeConcern: <document>,
collation: <document>
}
)
- filter
- 类型:document
- 描述
- 删除条件
- 通过查询操作符指定
- 如果指定一个空文档
{ }
,将删除集合中的所有文档
Returns
同 deleteOne
db.collection.find().pretty()
- 打印集合中的所有文档,并以更易读的方式显示
Operators
Query and Projection Operators
-
不包含字段 符合条件的操作符
\(ne、\)nin、\(nor、\)not
Comparison Operators
-
对大多数数据类型,仅当字段值类型和指定值类型相同时进行比较
不同时指定比较规则?
-
操作符表达式文档 本身 作为 字段/操作符 的值
$eq
- 指定相等条件,表示字段的值等于指定的值
- 如果字段为数组类型,则表示字段数组包含指定值的元素
- 如果指定的 value 是数组,则匹配的文档中,指定字段正好匹配数组 或 指定字段包含一个恰好匹配数组的元素(数组元素的顺序也要匹配)
格式
{ field: { $eq: value } }
// 等价于下面的写法
{ field: <value> }
- 可以省略 $eq ,即默认
field : value
形式就是相等条件
示例
db.inventory.find( { tags: { $eq: [ "A", "B" ] } } )
db.inventory.find( { tags: [ "A", "B" ] } )
db.inventory.find( { "item.name": { $eq: "ab" } } )
db.inventory.find( { "item.name": "ab" } )
$gt
- 指定大于条件,表示字段的值大于
>
指定的值(greater than)
格式
{field: {$gt: value} }
- 不可以省略,操作符表达式 作为一个子文档格式
示例
db.inventory.update( { "carrier.fee": { $gt: 2 } }, { $set: { price: 9.99 } } )
- 嵌套文档的 fee 字段的值大于2的 第一个文档将被添加一个 price 字段,值为 9.99
$gte
- 指定大于等于条件,表示字段的值大于等于
>=
指定的值(greater then or equal)
格式
{field: {$gte: value} }
$in
-
表示字段的值 等于 指定数组中任意一个元素
-
如果字段的值是数组类型,则表示字段数组 至少 包含 指定数组中任意一个元素
-
对同一个字段执行相等性检查时,优于 $or 逻辑操作符
-
可以通过正则对象表达式
/pattern/
指定匹配的值在 $in 表达式中不能使用 $regex 操作符表达式
格式
{ field: { $in: [<value1>, <value2>, ... <valueN> ] } }
- 值为数组类型
示例
-
字段值是数组
文档
{ _id: 1, item: "abc", qty: 10, tags: [ "school", "clothing" ], sale: false }
更新
db.inventory.update( { tags: { $in: ["appliances", "school"] } }, { $set: { sale:true } } )
- 更新条件是 tags 数组中至少包含 "appliances" 或 "school" 元素中的一个
-
正则表达式
db.inventory.find( { tags: { $in: [ /^be/, /^st/ ] } } )
- 如果 tags 是字符串,则匹配以 be 或 st 开头的字符串
- 如果 tags 是数组,则至少有一个元素是以 be 或 st 开头的字符串
$lt
- 指定小于条件,表示字段的值小于
<
指定的值(less than)
格式
{field: {$lt: value} }
$lte
- 指定小于等于条件,表示字段的值小于等于
<=
指定的值(less than or equal)
格式
{ field: { $lte: value} }
$ne
-
指定不相等条件,表示字段的值不等于指定的值,或者文档中 不包含该字段(not equal)
-
该操作符选择性不好,因为它经常匹配索引的很大一部分。因此,很多情况下,带有索引的 $ne 查询的性能并不比不带索引的 $ne 查询性能好
不带索引则必须扫描集合中所有的文档
格式
{field: {$ne: value} }
$nin
-
表示字段的值不等于指定数组中任何一个元素, 或者文档中 不包含该字段(not in)
-
如果字段的值是数组类型,则表示字段数组中不包含指定数组中任何一个元素
-
该操作符选择性不好,因为它经常匹配索引的很大一部分。因此,很多情况下,带有索引的 $nin 的查询性能并不比不带索引的 $nin 的查询性能好
不带索引则必须扫描集合中所有的文档
格式
{ field: { $nin: [ value1, value2 ... valueN ]}
- 值为数组类型
示例
db.inventory.update( { tags: { $nin: [ "appliances", "school" ] } }, { $set: { sale: false } } )
- 更新条件是 tags 数组中不包含 数组["appliances", "school"] 中的任意一个元素,或者文档中不包含 tags 字段
Logical Operators
$and
- 逻辑与,连接多个查询条件,表示文档必须符合所有条件
- 使用短路计算,如果第一个条件不符合则不再继续判断后续条件
- 以逗号分隔的表达式列表,也具有逻辑与操作(隐式 and )
格式
{ $and: [ { <expression1> }, { <expression2> } , ... , { <expressionN> } ] }
- 值为数组类型,元素为操作符表达式文档
- 本身不作为字段的值
示例
-
隐式and
db.inventory.find( { $and: [ { price: { $ne: 1.99 } }, { price: { $exists: true } } ] } )
相等于
将price字段的表达式重组,通过逗号分隔,组成一个表达式列表,用一个子文档表示
db.inventory.find( { price: { $ne: 1.99, $exists: true } } )
- 查询条件是:price 字段存在且值不等于 1.99 的文档
-
使用相同操作符的多个表达式
db.inventory.find( { $and: [ { $or: [ { qty: { $lt : 10 } }, { qty : { $gt: 50 } } ] }, { $or: [ { sale: true }, { price : { $lt : 5 } } ] } ] } )
- 使用了多次 $or 操作符,多个表达式,不能通过同一个字段的表达式重组的方式使用隐式and
- 查询条件是:qty字段的值小于10或大于50 且 sale字段为true或price字段的值小于5
$not
- 逻辑非,只用于一个查询条件,表示文档必须不符合该查询条件,或者不包含该字段
- 只能通过影响其他操作符来影响查询结果,不能独立检查字段和文档
格式
{ field: { $not: { <operator-expression> } } }
- 值为
-
操作符表达式文档
-
正则对象表达式
4.0.6版本之后才支持 正则操作符表达式
-
- 操作符表达式 本身 作为字段的值
示例
-
影响其他字段
db.inventory.find( { price: { $not: { $gt: 1.99 } } } )
- $gt 表示 price 大于 1.99 的文档,而加上 $not 则表示 price 小于或等于1.99 或 不包含 price 字段的文档
- 区别于 { $lte: 1.99 },表示 price 存在 且 price小于或等于1.99的文档
-
正则表达式
db.inventory.find( { item: { $not: /^p.*/ } } )
- 查询条件是:item 字段的值不以字符p开头的文档
-
正则操作符表达式
db.inventory.find( { item: { $not: { $regex: "^p.*" } } } ) db.inventory.find( { item: { $not: { $regex: /^p.*/ } } } ) db.inventory.find( { item: { $not: /^p.*/ } } )
- 查询条件是:item 字段的值不以字符p开头的文档
$nor
- 连接多个查询条件,表示文档必须不符合所有条件(and 操作符的反面),或者不包含该字段
格式
{ $nor: [ { <expression1> }, { <expression2> }, ... { <expressionN> } ] }
-
值为数组类型,元素为操作符表达式文档
-
操作符表达式 本身不作为字段的值
-
一般返回结果可以包括 2^表达式个数 个组合
每个表达式有两种情况,不符合表达式或不包含该字段
示例
-
一般情况
db.inventory.find( { $nor: [ { price: 1.99 }, { sale: true } ] } )
- 查询条件是:
1. price存在且不等于1.99 且 sale不为true
2. price不存在 且 sale 存在且不为true
3. price存在且不等于1.99 且 sale 不存在
4. price不存在 且 sale 不存在
- 结合 $exists 操作符使用
```sql
db.inventory.find( { $nor: [ { price: 1.99 }, { price: { $exists: false } },
{ sale: true }, { sale: { $exists: false } } ] } )
- $exists 操作符限制了 不包含字段 的情况
- 查询条件是:price存在且不等于1.99 且 sale存在且不为true
$or
- 逻辑或,连接多个查询条件,表示文档只要满足其中一个条件即可
- 对相同字段的检测使用 $in 操作符表达式比较好
格式
{ $or: [ { <expression1> }, { <expression2> }, ... , { <expressionN> } ] }
- 当对 $or 操作符表达式中的子句求值时,mongodb要么进行集合扫描,要么进行索引扫描(所有子句都必须建立索引)
示例
db.inventory.find( { $or: [ { quantity: { $lt: 20 } }, { price: 10 } ] } )
为了支持 $or 查询,需要给 quantity 和 price 字段建立索引
db.inventory.createIndex( { quantity: 1 } )
db.inventory.createIndex( { price: 1 } )
- 查询条件是
- quantity 字段的值小于20
- price字段的值等于10
Element Operators
$exists
- 表示某个字段是否存在
- SQL 中的 exists 操作相当于 mongodb 中的 $in
格式
{ field: { $exists: <boolean> } }
-
值为布尔类型
- true,表示存在该字段(包括字段值为null)
- false,表示不存在该字段
4.2 版本之前,$type:0 跟 $exists:false 是同义词
$type
-
表示字段的值是某个类型(BSON type ),或字段值是数组且包含一个该类型的元素
-
BSON type 可以是对应的数字或别名
-
当指定字段类型是数组时
- 3.6版本之前,返回字段是数组类型,并且至少包含一个数组元素的文档
- 3.6版本之后,返回字段是数组类型的文档(包括 空数组
[ ]
)
-
当字段类型
-
类型
Type Number Alias Notes Double 1 “double” String 2 “string” Object 3 “object” Array 4 “array” Binary data 5 “binData” Undefined 6 “undefined” Deprecated. ObjectId 7 “objectId” Boolean 8 “bool” Date 9 “date” Null 10 “null” Regular Expression 11 “regex” DBPointer 12 “dbPointer” Deprecated. JavaScript 13 “javascript” Symbol 14 “symbol” Deprecated. JavaScript (with scope) 15 “javascriptWithScope” 32-bit integer 16 “int” Timestamp 17 “timestamp” 64-bit integer 18 “long” Decimal128 19 “decimal” New in version 3.4. Min key -1 “minKey” Max key 127 “maxKey” $type : number
会匹配4中具体类型- double
- 32-bit integer(int)
- 64-bit integer(long)
- decimal
格式
{ field: { $type: <BSON type> } }
- 表示字段的值类型是指定的类型
{ field: { $type: [ <BSON type1> , <BSON type2>, ... ] } }
- 表示字段的值类型是指定类型中的任意一个
示例
-
单个类型
文档
db.addressBook.insertMany( [ { "_id" : 1, address : "2030 Martian Way", zipCode : "90698345" }, { "_id" : 2, address: "156 Lunar Place", zipCode : 43339374 }, { "_id" : 3, address : "2324 Pluto Place", zipCode: NumberLong(3921412) }, { "_id" : 4, address : "55 Saturn Ring" , zipCode : NumberInt(88602117) }, { "_id" : 5, address : "104 Venus Drive", zipCode : ["834847278", "1893289032"]} ] )
查询
db.addressBook.find( { "zipCode" : { $type : 2 } } ); db.addressBook.find( { "zipCode" : { $type : "string" } } );
-
将返回 zipCode 类型是字符串的文档 或 zipCode 类型是数组但包含一个字符串元素的文档
-
结果
{ "_id" : 1, "address" : "2030 Martian Way", "zipCode" : "90698345" } { "_id" : 5, "address" : "104 Venus Drive", "zipCode" : [ "834847278", "1893289032" ] }
-
-
多个类型
文档
db.grades.insertMany( [ { "_id" : 1, name : "Alice King" , classAverage : 87.333333333333333 }, { "_id" : 2, name : "Bob Jenkins", classAverage : "83.52" }, { "_id" : 3, name : "Cathy Hart", classAverage: ["94.06", 10] }, { "_id" : 4, name : "Drew Williams" , classAverage : NumberInt("93") } ] )
查询
db.grades.find( { "classAverage" : { $type : [ 2 , 1 ] } } ); db.grades.find( { "classAverage" : { $type : [ "string" , "double" ] } } );
-
将返回 classAverage 类型是字符串或double类型的文档 或 classAverage 类型是数组但包含一个字符串或double类型的元素
-
结果
{ "_id" : 1, name : "Alice King" , classAverage : 87.333333333333333 } { "_id" : 2, name : "Bob Jenkins", classAverage : "83.52" } { "_id" : 3, name : "Cathy Hart", classAverage: ["94.06", 10] }
-
Evaluation Operators
评估操作符
$expr
- 在查询语言中使用聚合表达式
格式
{ $expr: { <expression> } }
- 操作符表达式 本身不作为值
- expression 可以是任何有效的聚合表达式
示例
-
搭配比较聚合表达式
文档
{ "_id" : 1, "category" : "food", "budget": 400, "spent": 450 } { "_id" : 2, "category" : "drinks", "budget": 100, "spent": 150 } { "_id" : 3, "category" : "clothes", "budget": 100, "spent": 50 } { "_id" : 4, "category" : "misc", "budget": 500, "spent": 300 } { "_id" : 5, "category" : "travel", "budget": 200, "spent": 650 }
查询
db.monthlyBudget.find( { $expr: { $gt: [ "$spent" , "$budget" ] } } )
-
$gt 聚合表达式表示,第一个字段的值大于第二个字段的值返回true,否则返回false
-
结果
{ "_id" : 1, "category" : "food", "budget" : 400, "spent" : 450 } { "_id" : 2, "category" : "drinks", "budget" : 100, "spent" : 150 } { "_id" : 5, "category" : "travel", "budget" : 200, "spent" : 650 }
-
$jsonSchema
-
验证模式,用来数据校验
-
使用者必须具有 collMod 权限
https://docs.mongodb.com/v4.2/reference/command/collMod/#collmod
$mod
- 取摸运算,表示字段的值对 指定除数 取摸 具有 指定余数
格式
{ field: { $mod: [ divisor, remainder ] } }
- 值为 两个元素的 数组,元素个数不是2个会报错
示例
文档
{ "_id" : 1, "item" : "abc123", "qty" : 0 }
{ "_id" : 2, "item" : "xyz123", "qty" : 5 }
{ "_id" : 3, "item" : "ijk123", "qty" : 12 }
查询
db.inventory.find( { qty: { $mod: [ 4, 0 ] } } )
-
查询条件是:qty的值对4取摸余数为0
-
结果
{ "_id" : 1, "item" : "abc123", "qty" : 0 } { "_id" : 3, "item" : "ijk123", "qty" : 12 }
$text
- 对建立文本索引的所有字段进行文本搜索
- The $text operator, by default, does not return results sorted in terms of the results’ scores
- 限制
- 一个查询操作只能指定一个 $text 表达式
- 不能出现在 $nor 表达式中
- 不能出现在 $elemMatch 查询表达式 或 $elemMatch 投影表达式中
- 要在 $or 表达式中使用 $text 查询,则 $or 表达式中的所有子句都必须建立文本索引
- ......
- 视图不支持文本查询
- 聚合操作中
- 包含 $text 查询的 $match 阶段,必须是管道中的第一个阶段
- $text 查询在 stage 中只能出现一次
- 不能出现在 $or 或 $not 表达式中
- 默认情况下,文本搜索不会按照匹配分数的顺序返回匹配的文档。要按降序排序,请在 $sort 阶段使用 $meta 聚合表达式
格式
{
$text:
{
$search: <string>,
$language: <string>,
$caseSensitive: <boolean>,
$diacriticSensitive: <boolean>
}
}
-
$search
-
类型:字符串
-
描述:
-
mongodb 解析并用于查询文本索引的术语字符串
-
文本操作符将 $search 字符串中的大多数标点符号视为分隔符,但否定术语的连字符
-
和 指定短语的转义双引号\" \"
除外 -
转义双引号
-
匹配短语,需将短语括在转义双引号
\"
中"\"ssl certificate\""
-
如果 $search 字符串包含一个短语和单个术语,则文本查询只匹配包含短语的文档
"\"ssl certificate\" authority key"
$text 操作符将只匹配
"ssl certificate"
短语,忽略后面的单个术语 authority key
-
-
连字符
- 用于否定一个单词,将包含否定词的文档从结果集中排除(连字符前面要有空格)
- 当传递一个只包含否定词的搜索字符串时,文本搜索将不匹配任何文档
- 用连字符连接的词,例如 pre-market,不是否定词。$text 操作符将连字符视为分隔符(分别匹配两个术语),如果想表达否定含义,则在连接词的连字符前加一个空格,例如 pre -market
-
-
-
$language
- 类型:字符串
- 描述:指定搜索的停止词列表以及词干分析器和记号赋予器规则的语言。如果未指定,则搜索使用索引的默认语言
-
$caseSensitive
-
类型:布尔
-
描述:查询文本是否区分大小写
-
false【默认】
不区分
-
-
-
$diacriticSensitive
-
类型:布尔
-
描述:查询文本是否区别变音符
-
false【默认】
不区分
-
-
示例
文档
db.articles.createIndex( { subject: "text" } )
db.articles.insert(
[
{ _id: 1, subject: "coffee", author: "xyz", views: 50 },
{ _id: 2, subject: "Coffee Shopping", author: "efg", views: 5 },
{ _id: 3, subject: "Baking a cake", author: "abc", views: 90 },
{ _id: 4, subject: "baking", author: "xyz", views: 100 },
{ _id: 5, subject: "Café Con Leche", author: "abc", views: 200 },
{ _id: 6, subject: "Сырники", author: "jkl", views: 80 },
{ _id: 7, subject: "coffee and cream", author: "efg", views: 10 },
{ _id: 8, subject: "Cafe con Leche", author: "xyz", views: 10 }
]
)
-
查询单个术语
db.articles.find( { $text: { $search: "coffee" } } )
- 返回 subject 字段包含 "coffee" 的文档
-
查询用空格分隔的字符串
$text操作符对每个术语执行逻辑或搜索,并返回包含任何术语的文档。
db.articles.find( { $text: { $search: "bake coffee cake" } } )
-
返回 subject 字段包含 "bake" 或 "coffee" 或 "cake" 的文档
{ "_id" : 2, "subject" : "Coffee Shopping", "author" : "efg", "views" : 5 } { "_id" : 7, "subject" : "coffee and cream", "author" : "efg", "views" : 10 } { "_id" : 1, "subject" : "coffee", "author" : "xyz", "views" : 50 } { "_id" : 3, "subject" : "Baking a cake", "author" : "abc", "views" : 90 } { "_id" : 4, "subject" : "baking", "author" : "xyz", "views" : 100 }
- 注意 baking 也被匹配为 bake
-
-
查询短语
db.articles.find( { $text: { $search: "\"coffee shop\"" } } )
返回 subject 字段包含 "coffee shop" 的文档
{ "_id" : 2, "subject" : "Coffee Shopping", "author" : "efg", "views" : 5 }
-
否定单词
db.articles.find( { $text: { $search: "coffee -shop" } } )
-
返回 subject 字段包含 coffee,但不包含 shop 的文档
{ "_id" : 7, "subject" : "coffee and cream", "author" : "efg", "views" : 10 } { "_id" : 1, "subject" : "coffee", "author" : "xyz", "views" : 50 }
-
-
文档匹配分数
db.articles.find( { $text: { $search: "cake" } }, { score: { $meta: "textScore" } } )
返回
{ "_id" : 3, "subject" : "Baking a cake", "author" : "abc", "views" : 90, "score" : 0.75 }
- 返回的文档包含一个附加的 score 字段,该字段包含文档的匹配分数
$regex
-
在查询语言中使用正则表达式
mongodb 使用 PCRE 正则表达式
格式
正则操作符表达式
{ <field>: { $regex: /pattern/, $options: '<options>' } }
{ <field>: { $regex: 'pattern', $options: '<options>' } }
{ <field>: { $regex: /pattern/<options> } }
正则对象表达式
{ <field>: /pattern/<options> }
-
定界符可以使用 正斜杠 或 单引号
-
options
类型:字符串,只有省略操作符后可以不加单引号
-
i
忽略大小写
文档
{ "_id" : 100, "sku" : "abc123", "description" : "Single line description." } { "_id" : 101, "sku" : "abc789", "description" : "First line\nSecond line" } { "_id" : 102, "sku" : "xyz456", "description" : "Many spaces before line" } { "_id" : 103, "sku" : "xyz789", "description" : "Multiple\nline description" }
查询
db.products.find( { sku: { $regex: /^ABC/i } } )
匹配结果
{ "_id" : 100, "sku" : "abc123", "description" : "Single line description." } { "_id" : 101, "sku" : "abc789", "description" : "First line\nSecond line" }
-
m
-
对于包含锚点的模式(例如
^
表示开始,$
表示结束)文档
{ "_id" : 100, "sku" : "abc123", "description" : "Single line description." } { "_id" : 101, "sku" : "abc789", "description" : "First line\nSecond line" } { "_id" : 102, "sku" : "xyz456", "description" : "Many spaces before line" } { "_id" : 103, "sku" : "xyz789", "description" : "Multiple\nline description" }
查询
db.products.find( { description: { $regex: /^S/, $options: 'm' } } )
-
当数据为多行时,含有
\n
,设置 m 选项,则每行都单独匹配,任何一行符合条件即可匹配结果为
{ "_id" : 100, "sku" : "abc123", "description" : "Single line description." } { "_id" : 101, "sku" : "abc789", "description" : "First line\nSecond line" }
-
当数据为多行时,含有
\n
,没有设置 m 选项,则按一行进行匹配匹配结果为
{ "_id" : 100, "sku" : "abc123", "description" : "Single line description." }
-
-
对于不包含锚点的模式,或字符串没有分行,则按一行进行匹配, 设置 m 选项不起作用
db.products.find( { description: { $regex: /S/ } } )
-
正则表达式不包含
^ 或 $
-
匹配的结果为
{ "_id" : 100, "sku" : "abc123", "description" : "Single line description." } { "_id" : 101, "sku" : "abc789", "description" : "First line\nSecond line" }
-
-
-
x
忽略空格
使用x选项忽略空格和注释 (在匹配模式中以#开始,以\n结束)
文档
{ "_id" : 100, "sku" : "abc123", "description" : "Single line description." } { "_id" : 101, "sku" : "abc789", "description" : "First line\nSecond line" } { "_id" : 102, "sku" : "xyz456", "description" : "Many spaces before line" } { "_id" : 103, "sku" : "xyz789", "description" : "Multiple\nline description" }
查询
var pattern = "abc #category code\n123 #item number" db.products.find( { sku: { $regex: pattern, $options: "x" } } ) //=> pattern = "abc123"
匹配结果
{ "_id" : 100, "sku" : "abc123", "description" : "Single line description." }
-
s
允许
.
匹配所有的字符,包括换行符当数据为多行时,含有
\n
,将多行视为一行,换行符\n
被视为普通字符文档
{ "_id" : 100, "sku" : "abc123", "description" : "Single line description." } { "_id" : 101, "sku" : "abc789", "description" : "First line\nSecond line" } { "_id" : 102, "sku" : "xyz456", "description" : "Many spaces before line" } { "_id" : 103, "sku" : "xyz789", "description" : "Multiple\nline description" }
查询
db.products.find( { description: { $regex: /m.*line/, $options: 'si' } } )
匹配结果为
{ "_id" : 102, "sku" : "xyz456", "description" : "Many spaces before line" } { "_id" : 103, "sku" : "xyz789", "description" : "Multiple\nline description" }
- 点
.
匹配换行符,视为一行
不设置 s 选项,则匹配结果为
{ "_id" : 102, "sku" : "xyz456", "description" : "Many spaces before line" }
- 换行符无法匹配,视为多行
- 点
-
$regex vs. /pattern/ Syntax:{}
-
在 $in 操作符中,只能使用 JS正则对象表达式
{ name: { $in: [ /^acme/i, /^ack/ ] } }
-
以逗号分隔的多查询条件列表中,使用 $regex 正则操作符表达式
{ name: { $regex: /acme.*corp/i, $nin: [ 'acmeblahcorp' ] } } { name: { $regex: /acme.*corp/, $options: 'i', $nin: [ 'acmeblahcorp' ] } } { name: { $regex: 'acme.*corp', $options: 'i', $nin: [ 'acmeblahcorp' ] } }
-
要使用选项 ixsm,使用 $regex 正则操作符表达式
$where
3.6版本中 $expr 操作符允许在查询语言中使用聚合表达式,比where执行速度更快,因为不执行 JavaScript 代码,应首选 $expr
-
在查询语言中使用 JavaScript 表达式
使用 $where 操作符将包含 JavaScript表达式的字符串 或 完整的JavaScript函数传递给查询系统
-
集合中的每个文档都会执行 JavaScript表达式
-
在 JavaScript 表达式中通过 this 或 obj 引用文档
格式
{ $where: <JavaScript expression>
-
支持的属性和方法
Available Properties Available Functions args assert() isNumber() print() MaxKey BinData() isObject() printjson() MinKey DBPointer() ISODate() printjsononeline() DBRef() isString() sleep() doassert() Map() Timestamp() emit() MD5() tojson() gc() NumberInt() tojsononeline() HexData() NumberLong() tojsonObject() hex_md5() ObjectId() UUID() version()
示例
文档
{
_id: 12378,
name: "Steve",
username: "steveisawesome",
first_login: "2017-01-01"
}
{
_id: 2,
name: "Anya",
username: "anya",
first_login: "2001-02-02"
}
查询
db.players.find( { $where: function() {
return (hex_md5(this.name) == "9b53e667f30cd329dca1ec9e6a83e994")
} } );
-
$where 操作符的值是一个函数,集合中的每个文档都会执行该函数
-
结果
{ "_id" : 2, "name" : "Anya", "username" : "anya", "first_login" : "2001-02-02" }
Geospatial Operators
Array Operators
$all
- 表示字段的值为数组类型,且包含所有指定的元素
格式
{ <field>: { $all: [ <value1> , <value2> ... ] } }
- 值为 数组类型
示例
-
跟 $and 转换
{ tags: { $all: [ "ssl" , "security" ] } }
相当于,分别指定一个 $eq 表达式
{ $and: [ { tags: "ssl" }, { tags: "security" } ] }
$elemMatch
- 表示字段的值为数组类型,且至少有一个元素符合所有指定的条件
- 不能与 $where $text 操作符结合使用
格式
{ <field>: { $elemMatch: { <query1>, <query2>, ... } } }
- 如果只指定一个条件,则使用 $eq 较好
示例
-
元素匹配
{ _id: 1, results: [ 82, 85, 88 ] } { _id: 2, results: [ 75, 88, 89 ] }
查找
db.scores.find( { results: { $elemMatch: { $gte: 80, $lt: 85 } } } )
- 表示 results 数组中至少有一个元素满足 80 <= x < 85
$size
Bitwise Operators
Projection Operators
$
$elemMatch
$slice
Update Operators
https://docs.mongodb.com/manual/reference/operator/update-field/
- 更新操作中的一些操作符
Field Update Operators
- 更新操作中对字段的操作符
$currentDate
$inc
increments 增长
- 对指定字段的值进行加减运算
- 如果字段不存在,则会新增该字段,值为指定的值
- 如果对值为null的字段进行运算,会报错
- 针对单个文档的原子操作
格式
{ $inc: { <field1>: <amount1>, <field2>: <amount2>, ... } }
- amount 可以是正数 或 负数
$min
$max
$mul
$rename
-
更改指定字段名
-
如果 newName 已经存在与文档中,则会将该字段删除,然后再将指定字段名修改为 newName
相当于先对 old name 和 new name 执行 $unset 操作,然后再对 new name 执行 $set 操作
-
重命名的字段在文档中的顺序可能会改变
-
如果指定字段不存在,则什么都不做
-
对于嵌入文档中的字段,\(rename操作符可以重命名这些字段,也可以将字段移进或移出嵌入文档。如果这些字段在数组元素中,则\)rename不起作用
-
重命名,则 newName 也需要使用点表示法引用外层文档
db.students.update( { _id: 1 }, { $rename: { "name.first": "name.fname" } } )
-
移动,则 newName 不需要用点表示法引用外层文档
db.students.update( {_id:1}, { $rename: { "name.first":"fname" } })
将 fname 移动到顶层
-
格式
{$rename: { <field1>: <newName1>, <field2>: <newName2>, ... } }
- newName 必须与已经存在的字段名不同
- newName 类型是 字符串,需要加引号
示例
文档
db.students.insert([
{
"_id": 1,
"alias": [ "The American Cincinnatus", "The American Fabius" ],
"mobile": "555-555-5555",
"nmae": { "first" : "george", "last" : "washington" }
},
{
"_id": 2,
"alias": [ "My dearest friend" ],
"mobile": "222-222-2222",
"nmae": { "first" : "abigail", "last" : "adams" }
},
{
"_id": 3,
"alias": [ "Amazing grace" ],
"mobile": "111-111-1111",
"nmae": { "first" : "grace", "last" : "hopper" }
}
])
-
重命名
db.students.updateMany( {}, {$rename:{nmae:'name'}} )
-
移动字段
db.students.update( {_id:1}, { $rename: { "name.first":"fname" } } )
-
将 "name.first" 字段移动到外面,并重命名为 fname
结果为
{ "_id": 1, "alias": ["The American Cincinnatus", "The American Fabius"], "mobile": "555-555-5555", "name": { "last": "washington" }, "fname": "george" }
-
$set
- 替换指定字段的值
- 如果指定字段不存在,则新增该字段,值为指定的值(前提是不违反类型约束)
- 如果指定字段不存在,且为嵌套字段点表示法,则创建该嵌套文档以及字段,值为指定的值(前提同上)
- 如果指定了多个字段,则会更新或新增多个字段
格式
{ $set: { <field1>: <value1>, ... } }
若指定子文档或数组中的字段,则使用点表示法
数组
指定 contribs 中第三个元素,则表示为 contribs.2
{ ... contribs: [ "Turing machine", "Turing test", "Turingery" ], ... }
子文档
指定 last 字段,则表示为 name.last
指定 number 字段,则表示为 contact.phone.number
{ ... name: { first: "Alan", last: "Turing" }, contact: { phone: { type: "cell", number: "111-222-3333" } }, ... }
- 一级字段,不需要用双引号
- 多级字段,例如数组元素、子文档,需要用双引号
示例
文档
{
_id: 100,
sku: "abc123",
quantity: 250,
instock: true,
reorder: false,
details: { model: "14Q2", make: "xyz" },
tags: [ "apparel", "clothing" ],
ratings: [ { by: "ijk", rating: 4 } ]
}
更新操作
db.products.update(
{ _id: 100 },
{ $set:
{
quantity:500,
"details.make":"zzz",
"tags.1": "rain gear",
"ratings.0.rating": 2
}
}
)
$unset
- 删除指定的字段
- 如果字段不存在,则 $unset 什么事也不做
- 当与\(一起用于匹配数组元素时,\)unset将匹配元素替换为null,而不是从数组中删除。此行为保持数组大小和元素位置的一致性。
格式
{ $unset: { <field1>: "", ... } }
- 字段的值("")不影响操作,一般用空字符串代替
- 可以删除多个,用逗号隔开
- 嵌入式文档或数组中的字段使用点表示法
.
$setOnInsert
Array Update Operators
$
-
位置操作符,代表某个元素的位置(下标)
不需要指明具体的元素下标
-
当用于更新操作时
-
$
代表匹配更新条件的第一个元素下标 -
数组字段必须作为更新条件之一
通过对数组的操作,确定符合数组操作的第一个元素
虽然查询结果返回的是整个文档,但是在执行数组的操作时,会记录第一个符合数组过滤条件的元素
-
示例
-
元素类型为普通值时
{ "<array>.$" : value } }
db.students.insert([ { "_id" : 1, "grades" : [ 85, 80, 80 ] }, { "_id" : 2, "grades" : [ 88, 90, 92 ] }, { "_id" : 3, "grades" : [ 85, 100, 90 ] } ])
更新
db.students.updateOne( { grades: {$gte:89} }, { $set: { "grades.$" : 89 } } )
-
数组字段
grades
作为更新条件之一通过对数组的操作 {$gte:89},确定符合条件的文档以及第一个符合数组过滤条件的元素
-
在更新操作中用
$
代表符合条件的元素 -
更新
_id
为1,grades数组中包含 80 的文档,并将符合数组过滤条件的第一个元素值改为 89第一个文档的grades变为 [85, 82, 80]
-
-
元素类型为子文档时
{ "array.$.field" : value } }
{ _id: 4, grades: [ { grade: 80, mean: 75, std: 8 }, { grade: 85, mean: 90, std: 5 }, { grade: 85, mean: 85, std: 8 } ] }
更新
db.students.updateOne( { _id: 4, "grades.grade": 85 }, { $set: { "grades.$.std" : 6 } } )
$[]
New in version 3.6.
- 所有位置操作符,代表所有元素的位置(下标)
- 更新操作会作用于匹配条件的 数组中的 所有元素
- 官方文档中都添加了
multi: true
选项,但是测试不加也可以作用于所有元素
格式
db.collection.updateMany(
{ <query conditions> },
{ <update operator>: { "<array>.$[]" : value } }
)
示例
-
元素类型为普通值时
{ "<array>.$[]" : value } }
{ "_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)
-
元素类型为子文档时
{ "array.$[].field" : value } }
{ "_id" : 1, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 8 }, { "grade" : 85, "mean" : 90, "std" : 6 }, { "grade" : 85, "mean" : 85, "std" : 8 } ] } { "_id" : 2, "grades" : [ { "grade" : 90, "mean" : 75, "std" : 8 }, { "grade" : 87, "mean" : 90, "std" : 5 }, { "grade" : 85, "mean" : 85, "std" : 6 } ] }
更新
db.students2.update( { }, { $inc: { "grades.$[].std" : -2 } }, { multi: true } )
- 更新所有文档中grades数组中的每个元素所代表的子文档中的 std 字段(增加 -2)
-
结合过滤位置操作符
db.students3.insert([ { "_id" : 1, "grades" : [ { type: "quiz", questions: [ 10, 8, 5 ] }, { type: "quiz", questions: [ 8, 9, 6 ] }, { type: "hw", questions: [ 5, 4, 3 ] }, { type: "exam", questions: [ 25, 10, 23, 0 ] }, ] } ])
更新
db.students3.update( {}, { $inc: { "grades.$[].questions.$[score]": 2 } }, { arrayFilters: [ { "score": { $gte: 8 } } ], multi: true} )
- 更新所有文档中的grades数组中的每个元素所代表的子文档中的 questions 数组中的符合条件的元素
- 使用 arrayFilters 设定数组元素的的过滤条件
$[ <identifier> ]
New in version 3.6.
- 过滤位置操作符,代表符合条件的元素的位置
- 更新操作会作用于匹配条件的 数组中的 符合条件元素
- 结合 arrayFilters 选项使用
- <标识符> 必须以小写字母开头,且只包含字母、数字
格式
db.collection.updateMany(
{ <query conditions> },
{ <update operator> : { "<array>.$[<identifier>]" : value } },
{ arrayFilters: [ { <identifier>: <condition> } ] }
)
示例
-
元素类型为普通值时
{ "<array>.$[<identifier>]" : value } }
{ "_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 } } ] } )
- 更新操作中用 grades.$[element] 表示符合条件的元素
- arrayFilters 中用 element 代表元素,设定过滤条件
-
元素类型为子文档时
{ "array.$[<identifier>].field" : value }
{ "_id" : 1, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 6 }, { "grade" : 85, "mean" : 90, "std" : 4 }, { "grade" : 85, "mean" : 85, "std" : 6 } ] } { "_id" : 2, "grades" : [ { "grade" : 90, "mean" : 75, "std" : 6 }, { "grade" : 87, "mean" : 90, "std" : 3 }, { "grade" : 85, "mean" : 85, "std" : 4 } ] }
更新
db.students2.update( { }, { $set: { "grades.$[elem].mean" : 100 } }, { multi: true, arrayFilters: [ { "elem.grade": { $gte: 85 } } ] } )
- 更新所有文档中的grades数组中的符合条件的元素代表的子文档中的 mean 字段
- 符合条件的元素指,子文档中grade字段的值大于等于85
-
嵌套数组
db.students3.insert( { "_id" : 1, "grades" : [ { type: "quiz", questions: [ 10, 8, 5 ] }, { type: "quiz", questions: [ 8, 9, 6 ] }, { type: "hw", questions: [ 5, 4, 3 ] }, { type: "exam", questions: [ 25, 10, 23, 0 ] }, ] } )
更新
db.students3.update( {}, { $inc: { "grades.$[t].questions.$[score]": 2 } }, { arrayFilters: [ { "t.type": "quiz" } , { "score": { $gte: 8 } } ], multi: true} )
- 更新所有文档中的grades数组中的符合条件的元素代表的子文档中的questions数组中的符合条件的元素
- 条件1 { "t.type": "quiz" } ;条件2 { "score": { $gte: 8 } }
$addToSet
$pop
- 删除数组中的第一项或最后一项
- 指定值为 -1,则删除第一项
- 指定值为 1, 则删除最后一项
- 如果删除了数组中最后一个元素,则字段值为空数组
[ ]
- 如果指定字段的值不是数组,则操作失败
格式
{ $pop: { <field>: <-1 | 1>, ... } }
示例
文档
{ _id: 1, scores: [ 8, 9, 10 ] }
更新
db.students.update( { _id: 1 }, { $pop: { scores: -1 } } )
-
删除第一个元素
-
结果为
{ _id: 1, scores: [ 9, 10 ] }
$pull
-
删除数组中指定的值 或 所有符合条件的值
-
如果指定了 condition,且数组元素是嵌套文档,$pull 操作符会将每个嵌套子文档视为顶级文档进行 condition 匹配
- 如果是两层嵌套,不需要通过 $elemMatch 来指定内层字段的条件
- 如果是三层嵌套,则需要通过 $elemMatch 来指定内层字段的条件
-
如果指定的值 value 是数组,则 $pull 操作符将删除与 value 完全匹配的元素,包括元素顺序
-
如果指定的值 value 是文档,则 $pull 操作符将删除与 value 具有相同字段和值的元素,忽略字段顺序
格式
{ $pull: { <field1>: <value|condition>, <field2>: <value|condition>, ... } }
- condition 类型为操作符表达式文档
- value 类型为操作符表达式文档
示例
-
删除指定值
db.stores.update( { }, { $pull: { fruits: { $in: [ "apples", "oranges" ] }, vegetables: "carrots" } }, { multi: true } )
- value 为 \(in 操作符表达式 或 字符串(\)eq 操作符表达式)
-
删除满足条件的值
db.profiles.update( { _id: 1 }, { $pull: { votes: { $gte: 6 } } } )
- condition 为 $gte 操作符表达式
-
两层嵌套:数组元素是子文档
{ _id: 1, results: [ { item: "A", score: 5 }, { item: "B", score: 8, comment: "Strongly agree" } ] } { _id: 2, results: [ { item: "C", score: 8, comment: "Strongly agree" }, { item: "B", score: 4 } ] }
更新
db.survey.update( { }, { $pull: { results: { score: 8 , item: "B" } } }, { multi: true } )
-
condition 为 子文档
-
不需要通过 $elemMatch 指定
db.survey.update( { }, { $pull: { results: { $elemMatch: { score: 8 , item: "B" } } } }, { multi: true } )
不会删除任何元素
-
-
三层嵌套:数组元素是子文档,子文档字段是数组
{ _id: 1, results: [ { item: "A", score: 5, answers: [ { q: 1, a: 4 }, { q: 2, a: 6 } ] }, { item: "B", score: 8, answers: [ { q: 1, a: 8 }, { q: 2, a: 9 } ] } ] } { _id: 2, results: [ { item: "C", score: 8, answers: [ { q: 1, a: 8 }, { q: 2, a: 7 } ] }, { item: "B", score: 4, answers: [ { q: 1, a: 0 }, { q: 2, a: 8 } ] } ] }
更新
db.survey.update( { }, { $pull: { results: { answers: { $elemMatch: { q: 2, a: { $gte: 8 } } } } } }, { multi: true } )
$push
- 给数组末尾增加一个元素
- 如果文档中不存在指定的字段,则会新增该字段,值为仅包含指定值的数组
- 如果指定字段的值不是数组,则操作失败
- 如果指定的值是数组,则视为一个元素添加到指定字段数组中
格式
{ $push: { <field1>: <value1>, ... } }
结合修饰符
{ $push: { <field1>: { <modifier1>: <value1>, ... }, ... } }
示例
-
结合 $each 修饰符,将数组中的元素分别添加到指定字段
db.students.update( { name: "joe" }, { $push: { scores: { $each: [ 90, 92, 85 ] } } } )
- 用 $each 修饰要添加到指定字段的数组(值)
-
结合 $each $sort $slice
{ "_id" : 5, "quizzes" : [ { "wk": 1, "score" : 10 }, { "wk": 2, "score" : 8 }, { "wk": 3, "score" : 5 }, { "wk": 4, "score" : 6 } ] }
更新
db.students.update( { _id: 5 }, { $push: { quizzes: { $each: [ { wk: 5, score: 8 }, { wk: 6, score: 7 }, { wk: 7, score: 6 } ], $sort: { score: -1 }, $slice: 3 } } } )
-
$each
将数组 [ { wk: 5, score: 8 }, { wk: 6, score: 7 }, { wk: 7, score: 6 } ] 中的元素分别添加到 quizzes 数组中
-
$sort
将数组中的所有元素按照 score 字段的值降序排列
-
$slice
提出数组中前3个元素
-
$pullAll
$each
$position
$slice
$sort
Query Modifiers
$natural
- 自然顺序
- 与 cursor.hint() 联合使用,执行集合扫描以按自然顺序返回文档。
- 不能在 视图 中使用