MongoDB Shell中的数据类型与操作技巧
2022-08-287.2k 阅读
MongoDB Shell 中的数据类型
基本数据类型
- 字符串(String)
- 在 MongoDB 中,字符串是 UTF - 8 编码的字符序列。字符串必须用双引号(
"
)或单引号('
)括起来。例如:
db.users.insertOne({name: "John Doe"});
- 字符串类型常用于存储文本信息,如用户名、描述等。在查询时,可以使用各种字符串匹配操作符。例如,要查找名字以“J”开头的用户:
db.users.find({name: /^J/});
- 在 MongoDB 中,字符串是 UTF - 8 编码的字符序列。字符串必须用双引号(
- 数值(Number)
- MongoDB 支持多种数值类型。在 32 位系统上,默认的数值类型是
NumberInt
,它是 32 位有符号整数。例如:
db.products.insertOne({price: NumberInt(10)});
- 在 64 位系统上,默认的数值类型是
NumberLong
,用于表示 64 位有符号整数。对于浮点数,可以直接使用 JavaScript 的原生Number
类型,MongoDB 会将其存储为Double
类型。例如:
db.products.insertOne({weight: 1.5});
- 数值类型在各种计算和比较操作中广泛使用。例如,要查找价格大于 50 的产品:
db.products.find({price: {$gt: 50}});
- MongoDB 支持多种数值类型。在 32 位系统上,默认的数值类型是
- 布尔值(Boolean)
- 布尔类型只有两个值:
true
和false
。常用于表示逻辑状态,如用户是否激活、产品是否有库存等。例如:
db.users.insertOne({isActive: true});
- 在查询时,可以根据布尔值进行筛选。例如,查找所有激活的用户:
db.users.find({isActive: true});
- 布尔类型只有两个值:
- 日期(Date)
- 在 MongoDB Shell 中,日期类型通过
new Date()
创建。日期存储为自 Unix 纪元(1970 年 1 月 1 日 00:00:00 UTC)以来的毫秒数。例如:
var today = new Date(); db.orders.insertOne({orderDate: today});
- 可以对日期进行各种操作,如查找特定日期范围内的订单。例如,查找最近一周内的订单:
var oneWeekAgo = new Date(); oneWeekAgo.setDate(oneWeekAgo.getDate() - 7); db.orders.find({orderDate: {$gte: oneWeekAgo}});
- 在 MongoDB Shell 中,日期类型通过
- 空值(Null)
null
类型表示一个空值或不存在的值。在 MongoDB 中,它可用于表示文档中某个字段缺失或明确设置为空值。例如:
db.users.insertOne({bio: null});
- 在查询时,可以查找某个字段为
null
的文档。例如:
db.users.find({bio: null});
复合数据类型
- 数组(Array)
- 数组是值的有序集合。在 MongoDB 中,数组可以包含不同数据类型的元素。例如,可以创建一个包含字符串和数值的数组:
db.books.insertOne({ title: "Programming Languages", authors: ["John Smith", "Jane Doe"], ratings: [4, 5] });
- 数组在 MongoDB 中有强大的查询和更新操作。例如,要查找有“John Smith”作为作者的书籍:
db.books.find({authors: "John Smith"});
- 还可以使用数组操作符对数组进行更复杂的操作。例如,
$push
操作符用于向数组中添加元素:
db.books.updateOne( {title: "Programming Languages"}, {$push: {ratings: 3}} );
- 文档(Document)
- 文档是 MongoDB 中数据的基本组织单位,它是一个键值对的无序集合。文档可以嵌套,即一个文档的字段值可以是另一个文档。例如:
db.addresses.insertOne({ street: "123 Main St", city: "Anytown", state: "CA", zip: "12345", location: { lat: 37.7749, lon: -122.4194 } });
- 在查询嵌套文档时,需要使用点表示法。例如,要查找纬度大于 37 的地址:
db.addresses.find({"location.lat": {$gt: 37}});
- 对象 ID(ObjectId)
ObjectId
是 MongoDB 为每个文档自动生成的唯一标识符。它是一个 12 字节的 BSON 类型。ObjectId
的前 4 个字节表示文档创建的时间戳。例如,在插入文档时,MongoDB 会自动为其生成ObjectId
:
var result = db.users.insertOne({name: "Alice"}); var objectId = result.insertedId;
- 可以使用
ObjectId
进行文档的精确查找。例如:
db.users.find({_id: objectId});
- 在 JavaScript 中,可以通过
ObjectId
构造函数将字符串形式的ObjectId
转换为ObjectId
对象,以便进行查询。例如:
var objectIdStr = "5f4f7a9b9c8a370c50f9e57f"; var objectIdObj = ObjectId(objectIdStr); db.users.find({_id: objectIdObj});
MongoDB Shell 中的操作技巧
查询操作技巧
- 使用投影(Projection)限制返回字段
- 在查询时,默认会返回文档的所有字段。通过投影,可以选择只返回需要的字段。例如,要查找用户的名字和电子邮件,而不返回其他字段:
db.users.find({}, {name: 1, email: 1, _id: 0});
- 在投影中,将字段值设为 1 表示包含该字段,设为 0 表示排除该字段。
_id
字段比较特殊,默认是包含的,如果要排除,必须显式设置为 0。
- 复合查询条件(Logical Operators)
- 可以使用逻辑操作符(
$and
、$or
、$not
)组合多个查询条件。例如,要查找年龄大于 30 且城市为“New York”的用户:
db.users.find({ $and: [ {age: {$gt: 30}}, {city: "New York"} ] });
- 使用
$or
操作符查找年龄大于 30 或者城市为“New York”的用户:
db.users.find({ $or: [ {age: {$gt: 30}}, {city: "New York"} ] });
$not
操作符用于对单个条件取反。例如,查找年龄不大于 30 的用户:
db.users.find({age: {$not: {$gt: 30}}});
- 可以使用逻辑操作符(
- 范围查询(Range Queries)
- 除了
$gt
(大于)、$lt
(小于),还有$gte
(大于等于)、$lte
(小于等于)。例如,要查找价格在 50 到 100 之间(包括 50 和 100)的产品:
db.products.find({price: {$gte: 50, $lte: 100}});
- 除了
- 数组查询技巧
- 查询数组元素:可以直接查询数组中是否包含某个元素。例如,要查找有“JavaScript”标签的文章:
db.articles.find({tags: "JavaScript"});
- 查询数组长度:使用
$size
操作符可以查询具有特定长度的数组。例如,要查找有 3 个作者的书籍:
db.books.find({authors: {$size: 3}});
- 查询数组中的对象:如果数组元素是对象,可以使用点表示法查询对象的字段。例如,假设订单中的订单项是对象数组,要查找包含价格大于 10 的订单项的订单:
db.orders.find({"orderItems.price": {$gt: 10}});
更新操作技巧
- 原子更新操作符
$set
操作符:用于设置字段的值。例如,要更新用户的电子邮件:
db.users.updateOne( {name: "John Doe"}, {$set: {email: "john@example.com"}} );
$inc
操作符:用于对数值字段进行递增或递减。例如,要将产品的库存数量减少 5:
db.products.updateOne( {productName: "Widget"}, {$inc: {stock: -5}} );
$unset
操作符:用于删除字段。例如,要删除用户的 bio 字段:
db.users.updateOne( {name: "Jane Smith"}, {$unset: {bio: ""}} );
- 数组更新操作符
$push
操作符:如前文所述,用于向数组中添加元素。可以通过$each
修饰符一次添加多个元素。例如,要向文章的标签数组中添加多个标签:
db.articles.updateOne( {title: "MongoDB Tips"}, {$push: {tags: {$each: ["database", "nosql"]}}} );
$pull
操作符:用于从数组中删除符合条件的元素。例如,要从用户的爱好数组中删除“swimming”:
db.users.updateOne( {name: "Bob"}, {$pull: {hobbies: "swimming"}} );
$pop
操作符:用于从数组的开头或结尾删除一个元素。例如,要从订单的订单项数组中删除最后一个订单项:
db.orders.updateOne( {orderNumber: "12345"}, {$pop: {orderItems: -1}} );
- 这里
-1
表示从数组末尾删除,1
表示从数组开头删除。
聚合操作技巧
- 基本聚合操作
$group
操作符:用于按指定的字段对文档进行分组,并对每个组应用累加器函数。例如,要按城市统计用户数量:
db.users.aggregate([ {$group: {_id: "$city", count: {$sum: 1}}} ]);
- 在这个例子中,
_id
字段指定了分组依据,$sum
是累加器函数,用于计算每个组中的文档数量。 $match
操作符:用于在聚合管道中筛选文档,类似于find
方法中的查询条件。例如,要先筛选出年龄大于 30 的用户,再按城市统计数量:
db.users.aggregate([ {$match: {age: {$gt: 30}}}, {$group: {_id: "$city", count: {$sum: 1}}} ]);
- 复杂聚合操作
$lookup
操作符:用于执行左外连接,将来自不同集合的数据组合在一起。例如,假设有一个orders
集合和一个customers
集合,要在订单文档中添加对应的客户信息:
db.orders.aggregate([ {$lookup: { from: "customers", localField: "customerId", foreignField: "_id", as: "customerInfo" }} ]);
- 这里
from
指定要连接的集合,localField
是当前集合中的字段,foreignField
是连接集合中的字段,as
是结果数组的字段名。 $project
操作符:在聚合管道中用于投影,类似于查询中的投影。例如,在前面的聚合结果中,只保留订单号、客户姓名和订单金额:
db.orders.aggregate([ {$lookup: { from: "customers", localField: "customerId", foreignField: "_id", as: "customerInfo" }}, {$project: { orderNumber: 1, customerName: "$customerInfo.name", orderAmount: 1, _id: 0 }} ]);
索引操作技巧
- 创建索引
- 单字段索引:可以为单个字段创建索引以提高查询性能。例如,要为
users
集合的email
字段创建索引:
db.users.createIndex({email: 1});
- 这里
1
表示升序索引,-1
表示降序索引。 - 复合索引:当需要根据多个字段进行查询时,可以创建复合索引。例如,要根据
city
和age
字段创建复合索引:
db.users.createIndex({city: 1, age: -1});
- 复合索引的字段顺序很重要,查询条件应与索引字段顺序相匹配以获得最佳性能。
- 单字段索引:可以为单个字段创建索引以提高查询性能。例如,要为
- 索引管理
- 查看索引:可以使用
getIndexes
方法查看集合的所有索引。例如:
db.users.getIndexes();
- 删除索引:使用
dropIndex
方法删除不需要的索引。例如,要删除email
字段的索引:
db.users.dropIndex({email: 1});
- 重建索引:在某些情况下,如索引损坏或需要优化索引结构时,可以重建索引。例如:
db.users.reIndex();
- 查看索引:可以使用
性能优化技巧
- 查询优化
- 分析查询:使用
explain
方法分析查询的执行计划,了解查询如何使用索引等。例如:
db.users.find({age: {$gt: 30}}).explain("executionStats");
- 分析结果会显示查询的执行时间、扫描的文档数、是否使用索引等信息,帮助优化查询。
- 避免全表扫描:确保查询条件使用的字段有合适的索引,尽量避免查询条件中使用范围操作符(如
$gt
、$lt
)在索引字段的开头,因为这可能导致索引无法完全利用,从而引发全表扫描。
- 分析查询:使用
- 服务器配置优化
- 内存配置:MongoDB 依赖内存来缓存数据和索引,确保服务器有足够的内存分配给 MongoDB。可以通过修改配置文件(通常是
mongod.conf
)来调整内存相关参数,如wiredTiger.cache_sizeGB
用于设置 WiredTiger 存储引擎的缓存大小。 - 存储配置:选择合适的存储设备,如 SSD 可以显著提高 I/O 性能。此外,合理规划数据目录和日志目录,避免 I/O 竞争。
- 内存配置:MongoDB 依赖内存来缓存数据和索引,确保服务器有足够的内存分配给 MongoDB。可以通过修改配置文件(通常是
- 副本集和分片优化
- 副本集:合理配置副本集成员数量,确保有足够的冗余,同时避免过多成员导致性能开销。主节点和从节点的负载均衡也很重要,可以通过配置从节点的优先级和隐藏属性来优化。例如,将一些用于备份或分析的从节点设置为隐藏节点,避免它们参与读操作竞争。
- 分片:根据数据量和查询模式合理选择分片键,确保数据均匀分布在各个分片上。定期监控分片集群的状态,使用
sh.status()
命令查看分片的负载情况,必要时进行手动均衡操作。
通过深入理解 MongoDB Shell 中的数据类型和掌握各种操作技巧,可以更高效地使用 MongoDB 进行数据管理和应用开发。在实际应用中,应根据具体的业务需求和数据特点,灵活运用这些知识,以达到最佳的性能和功能实现。同时,持续关注 MongoDB 的版本更新,了解新的数据类型和操作特性,进一步提升开发和管理效率。