当前位置: 首页 > news >正文

MongoDB学习专题(二)核心操作

目录

1、复合主键

2、逻辑操作符匹配

1、$not

2、$and

2、$or

3、字段匹配

4、排序&分页查询&正则表达式查询

1、指定排序

2、分页查询

1、处理分页问题 – 巧分页

2、处理分页问题 – 避免使用 count

3、正则表达式匹配查询

6、更新文档

1、更新文档的操作符

2、更新单个文档

3、增减数值

4、更新多个文档

5、upsert命令

6、无操作符 update的 replace 语义

7、findAndModify命令

7、删除文档

1、使用 remove 删除文档

2、使用 delete 删除文档(推荐)

3、返回被删除文档


1、复合主键

可以使用文档作为复合主键

db.demeDoc.insert(
{_id: { product_name: 1,  // 主键字段1product_type: 2   // 主键字段2},supplierId: "001",  // 普通字段create_Time: new Date() // 自动生成时间戳
})

注意复合主键,字段顺序换了,会当做不同的对象被创建,即使内容完全一致

2、逻辑操作符匹配

$not(非(¬)) : 匹配筛选条件不成立的文档

$and(与(∧)): 匹配多个筛选条件同时满足的文档

$or (或(∨)​): 匹配至少一个筛选条件成立的文档

$nor(或非(¬∨)) : 匹配多个筛选条件全部不满足的文档

首先构造一组数据:

db.members.insertMany([
{nickName:"曹操",points:1000
},
{nickName:"刘备",points:500
}
]);

1、$not

用法:

{ field: { $not : { operator-expression} }}

积分不小于100 的

db.members.find({points: { $not: { $lt: 100}}} );

$not 也会筛选出并不包含查询字段的文档,相当于只会在自己领域用排除法

2、$and

用法

{ $and : [ condition expression1 , condition expression2 ..... ]}

1、昵称等于曹操, 积分大于 1000 的文档

db.members.find({$and : [ {nickName:{ $eq : "曹操"}}, {points:{ $gt:1000}}]});

2、当作用在不同的字段上时 可以省略 $and(nickName和points就不同)

db.members.find({nickName:{ $eq : "曹操"}, points:{ $gt:1000}});

3、当作用在同一个字段上面时可以简化为

db.members.find({points:{ $gte:1000, $lte:2000}});

2、$or

用法

{ $or :{ condition1, condition2, condition3,... }}
db.members.find(
{$or : [ {nickName:{ $eq : "刘备"}}, {points:{ $gt:1000}}]}
);

如果都是等值查询的话, $or 和 $in 结果是一样的

3、字段匹配

$exists:匹配包含查询字段的文档

{ field : {$exists:  <boolean>} }

比如上方的: 

db.members.find({points:{$exists:true}});返回结果:
[{_id: ObjectId('6891a8c446238faadaeec4ae'),nickName: '曹操',points: 1000},{_id: ObjectId('6891a8c446238faadaeec4af'),nickName: '刘备',points: 500}
]

4、排序&分页查询&正则表达式查询

1、指定排序

在 MongoDB 中使用 sort() 方法对数据进行排序

指定按收藏数(favCount)降序返回(1 为升序排列,而 -1 是用于降序排列)

db.books.find({type:"travel"}).sort({favCount:-1})

当同时应用 sort, skip, limit 时 ,应用的顺序为 sort, skip, limit 

2、分页查询

  • skip 用于指定跳过记录数
  • limit 用于限定返回结果数量

可以在执行find命令的同时指定skip、limit参数,以此实现分页的功能。

比如,假定每页大小为8条,查询第3页的book文档:

db.books.find().skip(8).limit(4)

1、处理分页问题 – 巧分页

数据量大的时候,应该避免使用skip/limit形式的分页。

替代方案:基于 ​​游标分页使用查询条件+唯一排序条件

例如:

第一页:
db.posts.find({}).sort({_id: 1}).limit(20);第二页:
db.posts.find({_id: {$gt: }}).sort({_id: 1}).limit(20);第三页:
db.posts.find({_id: {$gt: }}).sort({_id: 1}).limit(20);

2、处理分页问题 – 避免使用 count

尽可能不要计算总页数,特别是数据量大和查询条件不能完整命中索引时。

考虑以下场景:假设集合总共有 1000w 条数据,在没有索引的情况下考虑以下查询:

4.0+ 弃用方案:

(警告被丢弃:DeprecationWarning: Collection.count() is deprecated. Use countDocuments or estimatedDocumentCount)

//查询集合 coll中字段x等于100的文档,并限制返回结果最多 ​​50 条​​
db.coll.find({x: 100}).limit(50); //统计集合 coll中字段x等于100的文档总数
db.coll.count({x: 100}); 
  • 前者只需要遍历前 n 条,直到找到 50 条 x=100 的文档即可结束;
  • 后者需要遍历完 1000w 条找到所有符合要求的文档才能得到结果。 为了计算总页数而进行的 count() 往往是拖慢页面整体加载速度的原因

 方案1:使用 countDocuments()(精确计数)​

// 计算所有文档数量(等效于旧版 count())
db.members.countDocuments({});// 计算满足条件的文档数量(如 status: "A")
db.members.countDocuments({ status: "A" });

方案2:使用聚合管道 $count

// 统计跳过 1 条后限制 1 条的文档数(实际应用场景较少)
db.members.aggregate([{ $skip: 1 },{ $limit: 1 },{ $count: "total" }
]);

方案3:使用 estimatedDocumentCount()(快速估算)​

快速估算集合文档总数(忽略 skip/limit)

db.members.estimatedDocumentCount();

3、正则表达式匹配查询

MongoDB 使用 $regex 操作符来设置匹配字符串的正则表达式。

//使用正则表达式查找type包含 so 字符串的book
db.books.find({type:{$regex:"so"}})//或者
db.books.find({type:/so/})

6、更新文档

update命令对指定的数据进行更新,命令的格式如下:

db.collection.update(query,update,options)
  • query:更新的查询条件;
  • update:更新的动作及新的内容;
  • options:更新的选项

可选: 

  • upsert:如果不存在update的记录,是否插入新的记录。默认false,不插入
  • multi: 是否按条件查询出的多条记录全部更新。 默认false,只更新找到的第一条记录
  • writeConcern :决定一个写操作落到多少个节点上才算成功。

1、更新文档的操作符

操作符

格式

描述

$set

{$set:{field:value}}

指定一个键并更新值,若键不存在则创建

$unset

{$unset : {field : 1 }}

删除一个键

$inc

{$inc : {field : value } }

对数值类型进行增减

$rename

{$rename : {old_field_name : new_field_name } }

修改字段名称

$push

{ $push : {field : value } }

将数值追加到数组中,若数组不存在则会进行初始化

$pushAll

{$pushAll : {field : value_array }}

追加多个值到一个数组字段内

$pull

{$pull : {field : _value } }

从数组中删除指定的元素

$addToSet

{$addToSet : {field : value } }

添加元素到数组中,具有排重功能

$pop

{$pop : {field : 1 }}

删除数组的第一个或最后一个元素

2、更新单个文档

// 将 _id=1 的文档的 price 改为 699
db.products.update({ _id: 1 },{ $set: { price: 699 } }
)

3、增减数值

// 将 _id=2 的 stock 减少 2
db.products.update({ _id: 2 },{ $inc: { stock: -2 } }
)

4、更新多个文档

使用multi选项

multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新

// 将所有 tags 包含 "electronics" 的文档 price 增加 50
db.products.update({ tags: "electronics" },{ $inc: { price: 50 } },{ multi: true }
)

update命令的选项配置较多,为了简化使用还可以使用一些快捷命令:

  • updateOne:更新单个文档。
    // 将第一个 name 为 "Phone" 的文档的 price 改为 699
    db.products.updateOne({ name: "Phone" },{ $set: { price: 699 } }
    );
  • updateMany:更新多个文档。
    // 将所有 price < 800 的文档的 stock 增加 5
    db.products.updateMany({ price: { $lt: 800 } },{ $inc: { stock: 5 } }
    );
  • replaceOne:替换单个文档。
    // 将 _id: 1 的文档完全替换为新内容
    db.products.replaceOne({ _id: 1 },{ name: "Smartphone", price: 799, color: "black" }
    );

5、upsert命令

upsert是一种特殊的更新,其表现为如果目标文档不存在,则执行插入命令

旧指令:

// 如果 _id=3 不存在,则插入新文档
db.products.update({ _id: 3 },{ $set: { name: "Tablet", price: 299 } },{ upsert: true }
)

现代指令:

// 使用 updateOne 替代
db.books.updateOne({ title: "my book" },{ $set: { tags: ["nosql", "mongodb"],type: "none",author: "fox" }},{ upsert: true }
);

结果:

{acknowledged: true,                                // 操作已确认insertedId: ObjectId('6891c426ad6f8a20a28faffc'),  // 新插入文档的 _idmatchedCount: 0,                                   // 匹配的文档数(0 表示未找到)modifiedCount: 0,                                  // 修改的文档数upsertedCount: 1                                   // 插入的文档数
}

6、无操作符 update的 replace 语义

update命令中的更新描述(update)通常由操作符描述,如果更新描述中不包含任何操作符,那么MongoDB会实现文档的replace语义

db.books.update({title:"my book"},{justTitle:"my first book"}
)    
  • 若找到匹配文档,会用 { justTitle: "my first book" }​完全替换​​原文档(仅保留 _id)。

  • ​原文档的其他字段(如 tagsauthor)将被删除​​!

7、findAndModify命令

findAndModify兼容了查询和修改指定文档的功能,findAndModify只能更新单个文档

//将某个book文档的收藏数(favCount)加1
db.books.findAndModify({query:{_id:ObjectId("61caa09ee0782536660494dd")},update:{$inc:{favCount:1}}
})

该操作会返回符合查询条件的文档数据,并完成对文档的修改。

默认情况下,findAndModify会返回修改前的“旧”数据。如果希望返回修改后的数据,则可以指定new选项

db.books.findAndModify({query:{_id:ObjectId("61caa09ee0782536660494dd")},update:{$inc:{favCount:1}},new: true
})

与findAndModify语义相近的命令如下:

  • findOneAndUpdate:更新单个文档并返回更新前(或更新后)的文档。
  • findOneAndReplace:替换单个文档并返回替换前(或替换后)的文档。

7、删除文档

1、使用 remove 删除文档

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

示例:

db.user.remove({age:28})        // 删除age 等于28的记录 
db.user.remove({age:{$lt:25}})  // 删除age 小于25的记录 
db.user.remove( { } )           // 删除所有记录 db.user.remove() //报错

remove命令会删除匹配条件的全部文档,如果希望明确限定只删除一个文档,则需要指定justOne参数,命令格式如下:

db.collection.remove(query,justOne)

例如:删除满足type:novel条件的首条记录

db.books.remove({type:"novel"},true)
// 只删除第一条 name 以 "B" 开头的文档
db.users.remove({ name: /^B/ }, { justOne: true }
);

2、使用 delete 删除文档(推荐)

官方推荐使用 deleteOne() deleteMany() 方法删除文档,语法格式如下:

db.books.deleteMany ({})                //删除集合下全部文档
db.books.deleteMany ({ type:"novel" })  //删除 type等于 novel 的全部文档
db.books.deleteOne ({ type:"novel" })   //删除 type等于novel 的一个文档

注意: remove、deleteMany等命令需要对查询范围内的文档逐个删除,如果希望删除整个集合,则使用drop命令会更加高效

3、返回被删除文档

remove、deleteOne等命令在删除文档后只会返回确认性的信息,如果希望获得被删除的文档的完整信息,则可以使用findOneAndDelete命令

books 集合里,找到第一个类型是“novel”的书,然后把它删掉。在删除之后,它会返回这个被删除的文档

//在 books 集合里,找到第一个类型是“novel”的书,然后把它删掉。在删除之后,它会返回这个被删除的文档
db.books.findOneAndDelete({type:"novel"})

除了在结果中返回删除文档,findOneAndDelete命令还允许定义“删除的顺序”,即按照指定顺序删除找到的第一个文档

//根据 favCount 字段的值从小到大进行排序,删除排在最前面的那一个文档
db.books.findOneAndDelete({type:"novel"},{sort:{favCount:1}})

remove、deleteOne等命令只能按默认顺序删除,利用这个特性,findOneAndDelete可以实现队列的先进先出

http://www.dtcms.com/a/315750.html

相关文章:

  • MongoDB 从3.4.0升级到4.0.0完整指南实战-优雅草蜻蜓I即时通讯水银版成功升级-卓伊凡|bigniu
  • 时序数据库flux aggregateWindow命令详解
  • Baumer相机如何通过YoloV8深度学习模型实现道路场所路人口罩的检测识别(C#代码UI界面版)
  • 概率论之条件概率
  • ubuntu自动重启BUG排查指南
  • C++ - 仿 RabbitMQ 实现消息队列--服务端核心模块实现(六)
  • Go 单元测试:如何只运行某个测试函数(精确控制)
  • C++ 网络编程入门:TCP 协议下的简易计算器项目
  • 【STM32】HAL库中的实现(四):RTC (实时时钟)
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(14):文法:ていく+きた+单词
  • MQTT学习
  • Starrocks 关于 trace 命令的说明
  • C# --- 本地缓存失效形成缓存击穿触发限流
  • 【面向对象】面向对象七大原则
  • 【乐企板式文件生成工程】关于乐企板式文件(PDF/OFD/XML)生成工程介绍
  • [2401MT-B] 面积比较
  • 翻译的本质:人工翻译vs机器翻译的核心差异与互补性
  • Starrocks中的 Query Profile以及explain analyze及trace命令中的区别
  • MySQL 中 VARCHAR 和 TEXT 的区别
  • 智慧酒店:科技赋能下的未来住宿新体验
  • Spring-rabbit使用实战六
  • 国产三防平板电脑是什么?三防平板推荐
  • Spark内核调度
  • RTC实时时钟RX8900SA国产替代FRTC8900S
  • 使用maven-shade-plugin解决es跨版本冲突
  • 微信小程序功能实现:页面导航与跳转
  • jenkins插件Active Choices的使用通过参数动态控制多选参数的选项
  • LHA6958D是一款代替AD7606的芯片
  • 【前端】网站favicon图标制作
  • MyBatisPlus查询数据库中所有表的数据(AI)