// A sample document to insertconst newProduct ={name:"Wireless Mouse",brand:"Logitech",price:29.99,inStock:true};// Insert the new document into the 'products' collection
db.products.insertOne(newProduct);技术支持
insertMany()
该方法可一次性添加多个文档,比逐个插入高效得多。
// An array of documents to insertconst newProducts =[{name:"Mechanical Keyboard",brand:"Corsair",price:129.99,inStock:false},{name:"Gaming Headset",brand:"Razer",price:99.99,inStock:true},{name:"Webcam",brand:"LogiTech",price:79.99,inStock:true}];// Insert the array of documents into the 'products' collection
db.products.insertMany(newProducts);技术支持
// Find and return a cursor to all documents in the 'products' collection
db.products.find();技术支持
下面是在mongosh(MongoDB Shell)中该游标对象的示例,以及您可能与之交互的方式:
// Find all products and assign the returned cursor to a variableconst productCursor = db.products.find();// The variable 'productCursor' now holds the cursor object, not the documents themselves.// To get the documents, you need to iterate over the cursor.// You can convert the cursor to an array to see all the documentsconst allProducts = productCursor.toArray();
console.log(allProducts);// Or, you can manually iterate through the documentswhile(productCursor.hasNext()){const product = productCursor.next();
console.log(product);}技术支持
// Update the 'Wireless Mouse' document to set its price to 39.99
db.products.updateOne({name:"Wireless Mouse"},// Filter to find the document{$set:{price:39.99}}// Update operator);技术支持
updateMany()
该方法会更新匹配指定过滤条件的所有文档。
// Update all 'LogiTech' brand products to be in stock
db.products.updateMany({brand:"LogiTech"},// Filter to find the documents{$set:{inStock:true}}// Update operator);技术支持
// Find all products that are made by 'Razer'
db.products.find({brand:{$eq:"Razer"}});// This can be simplified to:// db.products.find({ brand: "Razer" });技术支持
$gt 与 $gte(大于、大于等于)
查找字段值大于($gt)或大于等于($gte)指定值的文档。
// Find all products with a price greater than 100
db.products.find({price:{$gt:100}});技术支持
$lt 与 $lte(小于、小于等于)
查找字段值小于($lt)或小于等于($lte)指定值的文档。
// Find all products with a price less than or equal to 50
db.products.find({price:{$lte:50}});技术支持
$ne(不等于)
$ne 查找字段不等于指定值的文档。
// Find all products that are NOT made by 'LogiTech'
db.products.find({brand:{$ne:"LogiTech"}});技术支持
$in 与 $nin(在数组中、不在数组中)
查找字段值位于($in)或不在($nin)指定值数组中的文档。
// Find all products from 'Razer' or 'Corsair'
db.products.find({brand:{ $in:["Razer","Corsair"]}});技术支持
逻辑操作符
逻辑操作符可组合多个条件以构建复杂查询。
$and
$and 使用逻辑与组合查询条件,所有条件均需为真。
// Find all products with a price greater than 50 AND are in stock
db.products.find({$and:[{price:{$gt:50}},{inStock:true}]});// This can be simplified by just listing the conditions:// db.products.find({ price: { $gt: 50 }, inStock: true });技术支持
$or
使用逻辑或组合查询条件,至少一个条件为真即可。
// Find all products with a brand of 'Corsair' OR a price less than 40
db.products.find({$or:[{brand:"Corsair"},{price:{$lt:40}}]});技术支持
元素与评估操作符
这些操作符提供了更灵活的过滤方式。
$exists
$exists 匹配包含特定字段的文档。
// Find all documents that have an 'inStock' field
db.products.find({inStock:{$exists:true}});技术支持
$regex
允许在字符串字段中使用正则表达式进行模式匹配。
// Find all product names that start with 'Wireless'
db.products.find({name:{$regex:/^Wireless/}});技术支持
// Group products by brand and calculate the total number of products for each brand
db.products.aggregate([{$group:{_id:"$brand",totalProducts:{$sum:1}}}]);技术支持
// Project a new field 'nameAndPrice' for each document
db.products.aggregate([{$project:{name:1,price:1,nameAndPrice:{$concat:["$name"," (","$price",")"]}}}]);技术支持
$sort
$sort 阶段会根据指定字段对文档重新排序。值为 1 表示升序,-1 表示降序。
// Sort all products by price in descending order
db.products.aggregate([{$sort:{price:-1}}]);技术支持
// Skip the first 10 products and then return the next 5
db.products.aggregate([{$skip:10},{$limit:5}]);技术支持
简单管道示例
下面是一个完整示例,展示这些阶段如何协同工作。
// Find the average price of all products that are currently in stock,// grouped by brand.
db.products.aggregate([{$match:{inStock:true}},// Filter for products in stock{$group:{_id:"$brand",averagePrice:{$avg:"$price"}}}// Group and calculate average price]);技术支持
// Conceptual illustration of performance difference// Without an index on 'brand':// MongoDB performs a full collection scan, checking every document.// This is slow, especially with millions of documents.
db.products.find({brand:"Razer"});// With an index on 'brand':// MongoDB uses the index to quickly locate and return only the matching documents.// This is very fast.
db.products.find({brand:"Razer"});技术支持
作为一款广受欢迎的 NoSQL 数据库,MongoDB 为数据管理提供了灵活且可扩展的方式。本文将带您从零开始掌握其直观的Query API,它允许您通过简洁的BSON(二进制 JSON)与数据交互,并针对效率与数据类型进行了优化。
在本文中,我们将讲解基础的创建、读取、更新、删除(CRUD)操作,深入精确查询中的过滤与投影,探索聚合管道在数据转换中的强大能力,并讨论通过索引来提升性能。读完后,您将具备在 MongoDB 集合中高效检索与操作数据的扎实基础。
基础概念:CRUD 操作
任何数据库交互的核心都是 CRUD:创建、读取、更新与删除。下面我们看看在 MongoDB 中如何完成这些操作。
创建数据(insert)
要向集合添加新文档,请使用insert 方法。MongoDB 中的文档是类 JSON 对象。
insertOne()
该方法用于向集合添加单个文档。
insertMany()
该方法可一次性添加多个文档,比逐个插入高效得多。
读取数据(find)
find() 方法是从集合检索文档的主要工具。调用find()时,并不会立刻返回所有文档本身,而是返回一个游标(cursor)。这是一种高效方式,可在不一次性将所有结果加载到内存的情况下处理潜在的大结果集。
最简单的find() 调用不带参数,返回指向集合中每个文档的游标。
下面是在mongosh(MongoDB Shell)中该游标对象的示例,以及您可能与之交互的方式:
游标本身是一个对象,包含诸如toArray()、hasNext() 和 next() 等方法,可用于检索并处理结果集中的文档。
更新数据(update)
要修改现有文档,请使用update 方法。这些方法接收两个主要参数:用于选择要更新文档的过滤条件(filter)与用于指定更改内容的更新操作符(update operator)。常见的操作符是$set,用于设置某个字段的值。
updateOne()
该方法更新匹配过滤条件的第一个文档。
updateMany()
该方法会更新匹配指定过滤条件的所有文档。
删除数据(delete)
要移除文档,请使用delete 方法。这些方法同样接受过滤条件来确定要删除的文档。
deleteOne()
该方法会删除匹配过滤条件的第一个文档。
deleteMany()
该方法会删除所有匹配过滤条件的文档。若要删除集合中的所有文档,可以传入空过滤条件{}。
精确检索:查询过滤器
查询过滤器是 MongoDB 强大能力的核心。它们是 find() 与 update 方法中的第一个参数,使您可以精确选择要处理的文档。
比较操作符
这些操作符用于将字段值与指定值进行比较。
$eq(等于)
查找字段等于某个值的文档。
$gt 与 $gte(大于、大于等于)
查找字段值大于($gt)或大于等于($gte)指定值的文档。
$lt 与 $lte(小于、小于等于)
查找字段值小于($lt)或小于等于($lte)指定值的文档。
$ne(不等于)
$ne查找字段不等于指定值的文档。$in 与 $nin(在数组中、不在数组中)
查找字段值位于($in)或不在($nin)指定值数组中的文档。
逻辑操作符
逻辑操作符可组合多个条件以构建复杂查询。
$and
$and使用逻辑与组合查询条件,所有条件均需为真。$or
使用逻辑或组合查询条件,至少一个条件为真即可。
元素与评估操作符
这些操作符提供了更灵活的过滤方式。
$exists
$exists匹配包含特定字段的文档。$regex
允许在字符串字段中使用正则表达式进行模式匹配。
塑造输出:投影(Projection)
执行find() 操作时,您可以仅返回每个文档的一部分字段。这称为投影(projection),它是传给find() 的第二个参数,有助于减少传输与处理的数据量。
包含字段
将要返回的字段值设为1 即可指定要返回的字段。
排除字段
相反地,将字段值设为0 可指定要隐藏的字段。
除非显式排除,否则_id 字段将默认返回。
_id 字段
若要隐藏_id 字段,必须显式将其设为0。
高级数据转换:聚合管道
聚合是 MongoDB 中功能强大的数据处理框架。聚合管道由一系列阶段组成,按顺序处理文档并将结果从一个阶段传递到下一个阶段。
$match
$match 阶段基于查询过滤器筛选文档,与 find() 类似。它通常作为第一阶段,用于减少需要处理的文档数量。
$group
$group 阶段根据指定的 _id 表达式对文档进行分组,并可执行多种累加操作,如对某字段求和或求平均值。
$project
$project 阶段会重塑数据流中的每个文档,类似于 find() 中的投影。您可以新增字段、移除现有字段,并对数据进行处理。
$sort
$sort 阶段会根据指定字段对文档重新排序。值为 1 表示升序,-1 表示降序。
$limit 与 $skip
这些阶段用于分页。$skip 会丢弃管道开头的指定数量文档,$limit 则限制传递到下一阶段的文档数量。
简单管道示例
下面是一个完整示例,展示这些阶段如何协同工作。
提升性能:索引
索引是特殊的数据结构,它们存储了集合数据中一小部分、易于遍历的内容。通过让 MongoDB 无需扫描整个集合即可快速定位并检索文档,索引能显著提升查询性能。
createIndex()
应在经常用于查询或排序的字段上创建索引。
数值 1 表示按升序建立索引。若为降序,可使用 -1,对按该方向排序的查询会更有利。
在类似 brand 的字段上创建索引,将使按 brand 过滤的查询(如 db.products.find({ brand: "Razer" }))在集合规模增长时依然能够快速执行。
选择索引字段的考量
通常应在查询中经常使用的字段上创建索引,例如 find() 的过滤条件或聚合的 $match 阶段中使用的字段。
对查询的影响
索引对性能影响巨大。带有索引的查询通常会比不带索引的同类查询快上数个数量级。
若需进一步优化查询,可以使用 db.collection.explain() 方法分析查询性能并查看索引的使用情况。
结语:迈向 MongoDB 熟练之路
您刚刚完成了 MongoDB Query API 的速成课程!现在,您已了解如何执行核心 CRUD 操作,使用强大的过滤器检索特定数据,通过投影塑造输出,并利用聚合管道转换数据。您也对通过索引提升性能有了基本认识。
本指南为您打下了坚实基础,而掌握这些概念的最佳方式就是实践。建议您多尝试不同的查询,并查阅完整文档以探索更高级的操作符与功能。编码愉快!