简介
Mongo和Mysql对比
使用node.js 连接 MongoDB
const { MongoClient } = require('mongodb');
// or as an es module:
// import { MongoClient } from 'mongodb'
// Connection URL
const url = 'mongodb://localhost:27017';
const client = new MongoClient(url);
// Database Name
const dbName = 'myProject';
async function main() {
// Use connect method to connect to the server
await client.connect();
console.log('Connected successfully to server');
const db = client.db(dbName);
const collection = db.collection('documents');
// the following code examples can be pasted here...
return 'done.';
}
main()
.then(console.log)
.catch(console.error)
.finally(() => client.close());
数据库管理语法 - 增删查
| 操作 | 语法 |
|---|---|
| 查看所有数据库 | show dbs; 或 show databases; |
| 查看当前数据库 | db; |
切换到某数据库 (若数据库不存在则创建数据库) | use <db_name>; |
| 删除当前数据库 | db.dropDatabase(); |
集合管理语法 - 增删查
| 操作 | 语法 |
|---|---|
| 查看所有集合 | show collections; |
| 创建集合 | db.createCollection("<collection_name>", options); |
| 删除集合 | db.<collection_name>.drop() |
| 重命名集合 | db.<collection_name>.renameCollection("<new_collection_name>") |
- 创建集合
db.createCollection("<collection_name>", options)中options参数如下:
| 参数名 | 类型 | 描述 |
|---|---|---|
capped | 布尔值 | 是否创建一个固定大小的集合。 |
size | 数值 | 集合的最大大小(以字节为单位)。仅在 capped 为 true 时有效。 |
max | 数值 | 集合中允许的最大文档数。仅在 capped 为 true 时有效。 |
validator | 对象 | 用于文档验证的表达式。 |
validationLevel | 字符串 | 指定文档验证的严格程度。 "off":不进行验证。 "strict":插入和更新操作都必须通过验证(默认)。 "moderate":仅现有文档更新时必须通过验证,插入新文档时不需要。 |
validationAction | 字符串 | 指定文档验证失败时的操作。 "error":阻止插入或更新(默认)。 "warn":允许插入或更新,但会发出警告。 |
storageEngine | 对象 | 为集合指定存储引擎配置。 |
collation | 对象 | 指定集合的默认排序规则。 |
db.createCollection("myComplexCollection", {
capped: true,
size: 10485760,
max: 5000,
validator: { $jsonSchema: {
bsonType: "object",
required: ["name", "email"],
properties: {
name: {
bsonType: "string",
description: "必须为字符串且为必填项"
},
email: {
bsonType: "string",
pattern: "^.+@.+$",
description: "必须为有效的电子邮件地址"
}
}
}},
validationLevel: "strict",
validationAction: "error",
storageEngine: {
wiredTiger: { configString: "block_compressor=zstd" }
},
collation: { locale: "en", strength: 2 }
});
文档管理语法 - 插入
| 方法 | 说明 |
|---|---|
db.<collection_name>.insertOne() | 将单个文档插入集合中。 |
db.<collection_name>.insertMany() | 将多个文档插入到一个集合中。 |
db.<collection_name>.insert()4.2+ 版本中已被标记为 废弃 | 既可以插入一条数据,也可以插入多条数据 |
db.<collection_name>.save() 4.2+ 版本中已被标记为 废弃 | 如果存在 _id 则更新,否则插入 |
- 插入单一文档
await db.collection('users').insertOne({
item: 'canvas',
qty: 100,
tags: ['cotton'],
size: { h: 28, w: 35.5, uom: 'cm' }
});
- 插入多个文档
await db.collection('users').insertMany([
{
item: 'journal',
qty: 25,
tags: ['blank', 'red'],
size: { h: 14, w: 21, uom: 'cm' }
},
{
item: 'mat',
qty: 85,
tags: ['gray'],
size: { h: 27.9, w: 35.5, uom: 'cm' }
},
{
item: 'mousepad',
qty: 25,
tags: ['gel', 'blue'],
size: { h: 19, w: 22.85, uom: 'cm' }
}
]);
文档管理语法 - 查询
| 方法 | 说明 |
|---|---|
db.<collection_name>.find(query, projection) | query:用于查找文档的查询条件。默认为 {},即匹配所有文档。projection(可选):指定返回结果中包含或排除的字段。 |
db.<collection_name>.findOne(query, projection) | findOne() 方法用于查找集合中的单个文档。如果找到多个匹配的文档,它只返回第一个 |
db.myCollection.find(
{ age: { $gt: 25 } },
{ name: 1, age: 1, _id: 0 }
);
db.myCollection.findOne({ name: "Alice" });
MongoDB 查询操作符与 MySQL 语法对照表
| 操作类别与说明 | MongoDB 操作符 | 示例与等价语法 |
|---|---|---|
| 比较操作符 | ||
| 等于 - 精确匹配 | $eq | MongoDB: db.users.find({ age: { $eq: 25 } }) MySQL: SELECT * FROM users WHERE age = 25 |
| 不等于 | $ne | MongoDB: db.users.find({ status: { $ne: "inactive" } })MySQL: SELECT * FROM users WHERE status <> 'inactive' |
| 大于 | $gt | MongoDB: db.products.find({ price: { $gt: 100 } }) MySQL: SELECT * FROM products WHERE price > 100 |
| 大于等于 | $gte | MongoDB: db.orders.find({ total: { $gte: 50 } }) MySQL: SELECT * FROM orders WHERE total >= 50 |
| 小于 | $lt | MongoDB: db.students.find({ score: { $lt: 60 } }) MySQL: SELECT * FROM students WHERE score < 60 |
| 小于等于 | $lte | MongoDB: db.employees.find({ level: { $lte: 3 } })MySQL: SELECT * FROM employees WHERE level <= 3 |
| 逻辑操作符 | ||
| 与 - 多条件同时满足 | $and | MongoDB: db.users.find({ $and: [ { age: { $gt: 18 } }, { status: "active" } ] }) MySQL: SELECT * FROM users WHERE age > 18 AND status = 'active' |
| 或 - 任一条件满足 | $or | MongoDB: db.products.find({ $or: [ { category: "book" }, { price: { $lt: 20 } } ] })MySQL: SELECT * FROM products WHERE category = 'book' OR price < 20 |
| 非 - 取反操作 | $not | MongoDB: db.customers.find({ age: { $not: { $gt: 30 } } }) MySQL: SELECT * FROM customers WHERE NOT age > 30 |
| 或非 - 所有条件都不满足 | $nor | MongoDB: db.logs.find({ $nor: [ { type: "error" }, { priority: { $gte: 5 } } ] })MySQL: SELECT * FROM logs WHERE NOT (type = 'error' OR priority >= 5) |
| 元素操作符 | ||
| 字段存在 - 检查字段是否存在 | $exists | MongoDB: db.users.find({ phone: { $exists: true } }) MySQL: SELECT * FROM users WHERE phone IS NOT NULL |
| 字段类型 - 按BSON类型查询 | $type | MongoDB: db.data.find({ value: { $type: "decimal" } })MySQL: SELECT * FROM data WHERE JSON_TYPE(value) = 'DECIMAL' |
| 数组操作符 | ||
| 包含所有元素 - 数组包含指定所有元素 | $all | MongoDB: db.products.find({ tags: { $all: ["sale", "new"] } })MySQL: SELECT * FROM products WHERE JSON_CONTAINS(tags, '["sale","new"]') |
| 数组长度 - 按数组长度查询 | $size | MongoDB: db.orders.find({ items: { $size: 3 } }) MySQL: SELECT * FROM orders WHERE JSON_LENGTH(items) = 3 |
| 元素匹配 - 数组元素同时满足多个条件 | $elemMatch | MongoDB: db.scores.find({ results: { $elemMatch: { $gt: 80, $lt: 90 } } }) MySQL: SELECT * FROM scores WHERE EXISTS (SELECT 1 FROM JSON_TABLE(results, ...) WHERE value > 80 AND value < 90) |
| 评估操作符 | ||
| 正则表达式 - 模式匹配 | $regex | MongoDB: db.users.find({ name: { $regex: /^ali/i } }) MySQL: SELECT * FROM users WHERE name REGEXP '^ali' |
| 全文搜索 - 文本索引搜索 | $text | MongoDB: db.articles.find({ $text: { $search: "database -mongodb" } }) MySQL: SELECT * FROM articles WHERE MATCH(content) AGAINST('+database -mongodb' IN BOOLEAN MODE) |
| 聚合表达式 - 使用聚合表达式查询 | $expr | MongoDB: db.sales.find({ $expr: { $gt: ["$revenue", "$cost"] } }) MySQL: SELECT * FROM sales WHERE revenue > cost |
| 字段操作符 | ||
| 定位符 - 更新匹配的数组元素 | $ | MongoDB: db.users.update({ "addresses.city": "Berlin" }, { $set: { "addresses.$.zip": "10115" } })MySQL: 无直接等价(需应用层处理) |
| 数组切片 - 返回数组的子集 | $slice | MongoDB: db.posts.find({}, { comments: { $slice: 5 } }) MySQL: SELECT id, JSON_EXTRACT(comments, '$[0 to 4]') AS comments FROM posts |
| 地理空间操作符 | ||
| 地理范围内 - 多边形内点查询 | $geoWithin | MongoDB: db.places.find({ loc: { $geoWithin: { $geometry: { type: "Polygon", coordinates: [...] } } } }) MySQL: SELECT * FROM places WHERE ST_Within(loc, ST_GeomFromText('POLYGON(...)')) |
| 邻近点 - 按距离排序查询 | $near | MongoDB: db.stores.find({ location: { $near: { $geometry: { type: "Point", coordinates: [13.4,52.5] } } })MySQL: SELECT * FROM stores ORDER BY ST_Distance(location, ST_SRID(Point(13.4,52.5),4326)) LIMIT 10 |
特殊查询操作符详解
- 嵌套文档查询
| 操作 | MongoDB | MySQL |
|---|---|---|
| 精确匹配嵌套文档 | db.users.find({ "address.city": "Berlin" }) | SELECT * FROM users WHERE address->>'$.city' = 'Berlin' |
| 嵌套文档多条件 | db.users.find({ "address.city": "Berlin", "address.zip": "10115" }) | SELECT * FROM users WHERE address->>'$.city' = 'Berlin' AND address->>'$.zip' = '10115' |
- 数组元素查询
| 操作 | MongoDB | MySQL |
|---|---|---|
| 索引位置匹配 | db.users.find({ "hobbies.0": "skiing" }) | SELECT * FROM users WHERE JSON_EXTRACT(hobbies, '$[0]') = 'skiing' |
| 任意位置匹配 | db.users.find({ hobbies: "skiing" }) | SELECT * FROM users WHERE JSON_CONTAINS(hobbies, '"skiing"') |
- 组合查询
// MongoDB 组合查询
db.employees.find({
$and: [
{ $or: [ { dept: "HR" }, { dept: "Finance" } ] },
{ salary: { $gt: 5000 } },
{ join_date: { $gt: new Date("2020-01-01") } }
]
})
-- MySQL 等价查询
SELECT * FROM employees
WHERE (dept = 'HR' OR dept = 'Finance')
AND salary > 5000
AND join_date > '2020-01-01'
- 分页与排序操作
| 操作 | MongoDB | MySQL |
|---|---|---|
| 排序 | // 按 price 字段升序排序 db.products.find().sort({ price: -1 })1 表示升序,-1 表示降序 | SELECT * FROM products ORDER BY price DESC |
| 分页 | limit() 方法用于限制查询结果返回的文档数量 skip() 方法用于跳过指定数量的文档,从而实现分页或分批查询db.orders.find().skip(20).limit(10) | SELECT * FROM orders LIMIT 10 OFFSET 20 |
| 复合排序 | db.users.find().sort({ age: 1, name: -1 }) | SELECT * FROM users ORDER BY age ASC, name DESC |
- 聚合操作符对比
| 操作 | MongoDB 聚合 | MySQL 聚合 |
|---|---|---|
| 分组计数 | db.sales.aggregate([ { $group: { _id: "$product", total: { $sum: 1 } } ]) | SELECT product, COUNT(*) AS total FROM sales GROUP BY product |
| 平均值 | db.grades.aggregate([ { $group: { _id: null, avg: { $avg: "$score" } } ]) | SELECT AVG(score) AS avg FROM grades |
| 最大值 | db.stats.aggregate([ { $group: { _id: null, max: { $max: "$value" } } ]) | SELECT MAX(value) AS max FROM stats |
-
聚合管道
介绍: 通过
管道(pipeline)方式对文档进行多级转换和计算。与简单查询相比,聚合能处理复杂的数据分析任务,如下:1、
$project:修改输入文档的结构。可以用来重命名、增加或删除域,也可以用于创建计算结果以及嵌套文档。db.<collection_name>.aggregate({ $project: { _id: 0, product: 1, total: { $multiply: ["$price", "$quantity"] }, discount: { $cond: { if: "$isVIP", then: 0.2, else: 0 } } } })2、
$match用于过滤数据,只输出符合条件的文档。$match使用MongoDB的标准查询操作。db.<collection_name>.aggregate({ $match: { status: "A", qty: { $gt: 20 } } })3、
$limit:用来限制MongoDB聚合管道返回的文档数。4、
$skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。5、
$unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。db.<collection_name>.aggregate({ $unwind: { path: "$tags", // 数组字段路径 includeArrayIndex: "idx", // 添加索引字段 preserveNullAndEmptyArrays: true // 保留空数组文档 } })6、
$group:将集合中的文档分组,可用于统计结果。db.<collection_name>.aggregate({ $group: { _id: "$category", // 分组键 totalSales: { $sum: "$amount" }, avgPrice: { $avg: "$price" }, topProduct: { $max: "$product" }, uniqueCustomers: { $addToSet: "$customerId" } } })7、
$sort:将输入文档排序后输出。8、
$geoNear:输出接近某一地理位置的有序文档。 -
表达式运算符
类型 示例 说明 算术 $add,$sqrt数学计算 日期 $year,$dateDiff日期提取/计算 字符串 $substr,$trim文本处理 逻辑 $and,$switch条件判断 数组 $size,$map数组操作
文档管理语法 - 更新
- 基础
| 方法 | 描述 | 示例 |
|---|---|---|
updateOne() | 更新单个文档 | db.users.updateOne({name:"Alice"}, {$set: {age:26}}) |
updateMany() | 更新所有匹配文档 | db.products.updateMany({stock:0}, {$set: {status:"discontinued"}}) |
replaceOne() | 替换整个文档(除_id外) | db.users.replaceOne({_id:1}, {name:"Alice", role:"admin"}) |
update() | 5.0+ 版本中已被标记为废弃 | db.users.update({name:"Bob"}, {$inc: {loginCount:1}}) |
db.<collection_name>.updateOne(
<filter>, #update的查询条件,类似sql update语句where后面的部分
<update>, #update的对象和一些更新的操作符等,也可以理解为sql update语句set后面的
{
upsert: <boolean>, // 可选:不存在则插入(默认false)
writeConcern: <document>, // 可选:写关注设置
collation: <document>, // 可选:排序规则
arrayFilters: [ <filter> ], // 可选:数组元素过滤
hint: <document|string> // 可选:强制使用索引
}
)
- 批量修改
db.<collection_name>.bulkWrite()
// 批量写入操作
db.collection.bulkWrite([
{ updateOne: {
filter: {status:"pending"},
update: {$set: {status:"processed"}}
}},
{ updateMany: {
filter: {qty: {$lt:10}},
update: {$inc: {qty:5}}
}}
])
- 字段更新操作符
| 操作符 | 功能 | 示例 |
|---|---|---|
$set | 设置字段值 | {$set: {status:"active", lastLogin: new Date()}} |
$unset | 删除字段 | {$unset: {temporaryFlag: ""}} |
$inc | 数值增减 | {$inc: {balance: 50, loginCount:1}} |
$mul | 数值乘法 | {$mul: {price: 0.9}} // 打9折 |
$rename | 重命名字段 | {$rename: {"oldName": "newName"}} |
$min | 仅当新值更小时更新 | {$min: {lowestPrice: 99}} |
$max | 仅当新值更大时更新 | {$max: {highestScore: 95}} |
$currentDate | 设置当前日期 | {$currentDate: {lastModified: true}} |
- 数组更新操作符
| 操作符 | 功能 | 示例 |
|---|---|---|
$push | 添加元素到数组 | {$push: {tags: "new"}} |
$pop | 移除首尾元素(1:尾, -1:首) | {$pop: {queue: 1}} // 移除末尾元素 |
$pull | 移除匹配元素 | {$pull: {tags: "obsolete"}} |
$pullAll | 移除多个元素 | {$pullAll: {scores: [0,5]}} |
$addToSet | 添加唯一元素 | {$addToSet: {emails: "alice@example.com"}} |
$each | 配合$push/$addToSet添加多个元素 | {$push: {log: {$each: [1,2,3], $slice:-10}}} // 保留最后10个元素 |
$position | 指定插入位置 | {$push: {list: {$each: ["A"], $position:0}}} // 插入开头 |
$sort | 数组排序 | {$push: {scores: {$each:[], $sort:1}}} // 升序排序 |
- 数组定位操作符
| 操作符 | 功能 | 示例 |
|---|---|---|
$ | 匹配第一个符合条件的数组元素 | db.users.update({"grades.score":90}, {$set:{"grades.$.status":"A"}}) |
$[] | 匹配所有数组元素 | db.products.update({}, {$inc:{"reviews.$[].rating":1}}) |
$[elem] | 过滤指定条件的数组元素 | db.users.update({}, {$set:{"grades.$[g].curve":true}},<br> {arrayFilters:[{"g.score":{$gt:90}}]}) |
文档管理语法 - 删除
| 方法 | 说明 |
|---|---|
db.<collection_name>.deleteOne(filter, options) | 删除单个文档 |
db.<collection_name>.deleteMany(filter, options) | 删除所有匹配过滤器的文档 |
filter:用于查找要删除的文档的查询条件。options(可选):一个可选参数对象 :writeConcern:指定写操作的确认级别。collation:指定比较字符串时使用的排序规则。projection(仅适用于findOneAndDelete):指定返回的字段。sort(仅适用于findOneAndDelete):指定排序顺序以确定要删除的文档。
db.myCollection.deleteOne({ name: "Alice" });
db.users.deleteOne(
{ name: "alice" },
{ collation: { locale: "en", strength: 2 } } // 不区分大小写
)
db.myCollection.deleteMany({ status: "inactive" });
db.users.deleteMany(
{ status: "expired" },
{ writeConcern: { w: "majority", wtimeout: 5000 } } // 5秒超时
)
数据类型
- MongoDB 支持丰富的
BSON 数据类型(Binary JSON),比标准的 JSON 类型更强大。以下是所有数据类型的详细说明和示例:
一、基础数据类型
| 类型 | 常量标识符 | 说明 | 示例 |
|---|---|---|---|
| String | string | UTF-8 字符串 | { "name": "Alice" } |
| Integer | int | 32 位或 64 位整数(自动判定) | { "age": 30 } |
| Double | double | 双精度浮点数 | { "price": 19.99 } |
| Boolean | bool | 布尔值 | { "is_active": true } |
| Null | null | 空值 | { "description": null } |
二、特殊数值类型
| 类型 | 常量标识符 | 说明 | 示例 |
|---|---|---|---|
| NumberInt | int | 强制 32 位整数 | { "count": NumberInt(50) } |
| NumberLong | long | 强制 64 位整数 | { "population": NumberLong(10000000000) } |
| NumberDecimal | decimal | 高精度小数(金融计算) | { "total": NumberDecimal("100.5000") } |
三、日期与时间
| 类型 | 说明 | 示例 |
|---|---|---|
| Date | UTC 日期时间(毫秒精度) | { "created": new Date() } |
| Timestamp | 内部操作时间戳(非通用) | { "ts": Timestamp(114215, 1) } |
注意:
Date()存储为 UTC 时间:ISODate("2023-10-01T12:30:00Z")Timestamp格式:Timestamp(t, i)(t=秒数,i=递增计数器)
四、复合数据类型
- Object (Embedded Document)
{
"address": {
"street": "123 Main St",
"city": "Berlin",
"zip": "10115"
}
}
- Array
{
"tags": ["mongodb", "database", "nosql"],
"scores": [98, 87, 92]
}
- ObjectId
{
"_id": ObjectId("507f1f77bcf86cd799439011") // 12字节唯一ID
}
结构:
时间戳(4) + 机器ID(3) + 进程ID(2) + 计数器(3)
五、二进制数据
| 类型 | 说明 | 示例 |
|---|---|---|
| BinData | 存储二进制数据 | { "file": BinData(0, "SGVsbG8gd29ybGQ=") } |
| UUID | 通用唯一标识符 | { "uuid": UUID("b5c1c6a0-7e93-4a8e-9c3d-1f2b4c5d6e7f") } |
BinData 子类型:
0:通用二进制1:函数3:UUID(旧版)4:UUID(RFC 4122)5:MD5
六、地理空间类型
| 类型 | 格式 | 示例 |
|---|---|---|
| Point | { type: "Point", coordinates: [x,y] } | { loc: { type: "Point", coordinates: [13.4, 52.5] } } |
| LineString | 坐标点数组 | { path: { type: "LineString", coordinates: [[0,0], [1,1]] } } |
| Polygon | 闭合坐标环 | { area: { type: "Polygon", coordinates: [[[0,0],[3,0],[3,3],[0,3],[0,0]]] } } |
七、特殊功能类型
| 类型 | 说明 | 示例 |
|---|---|---|
| Regular Expression | 正则表达式 | { pattern: /^MongoDB/i } |
| JavaScript | 存储 JavaScript 代码 | { func: function() { /* logic */ } } |
| Symbol | 已弃用(类似字符串) | { key: Symbol("deprecated") } |
| Min/Max Key | 内部比较使用 | { min: MinKey(), max: MaxKey() } |
八、类型检查与转换
- 查看字段类型
// 返回字段类型字符串
typeof db.users.findOne().age // 返回 "number"
// 使用 $type 操作符查询
db.users.find({ age: { $type: "int" } })
- 类型标识符对照表
| 类型名 | 数字标识符 | 字符串标识符 |
|---|---|---|
| Double | 1 | "double" |
| String | 2 | "string" |
| Object | 3 | "object" |
| Array | 4 | "array" |
| BinData | 5 | "binData" |
| ObjectId | 7 | "objectId" |
| Boolean | 8 | "bool" |
| Date | 9 | "date" |
| Null | 10 | "null" |
| Regular Expression | 11 | "regex" |
| 32-bit Integer | 16 | "int" |
| Timestamp | 17 | "timestamp" |
| 64-bit Integer | 18 | "long" |
| Decimal128 | 19 | "decimal" |
| MinKey | -1 | "minKey" |
| MaxKey | 127 | "maxKey" |
九、使用注意事项
-
类型敏感查询
// 整数 30 不等于 双精度 30.0 db.users.find({ age: 30 }) // 匹配 {age: 30} 但不匹配 {age: 30.0} db.users.find({ age: 30.0 }) // 只匹配双精度值 -
日期处理
// 按日期范围查询 db.orders.find({ created: { $gte: ISODate("2023-01-01"), $lt: ISODate("2023-02-01") } }) -
Decimal 精度
// 金融计算必须用 Decimal128 { price: NumberDecimal("9.99") } // 精确存储 { price: 9.99 } // 双精度可能有误差 -
对象比较
// 嵌入式文档需完全匹配 db.users.find({ address: { city: "Berlin", zip: "10115" } }) // 不匹配 { address: { zip: "10115", city: "Berlin" } } (字段顺序敏感)
十、数据类型使用示例
// 完整文档示例
{
_id: ObjectId("64d5ec9f8e1c2a2b00e8b7f1"),
name: "MongoDB Atlas",
version: 6.0,
release_date: ISODate("2023-07-10T00:00:00Z"),
features: ["ACID", "Encryption", "Search"],
pricing: {
free_tier: true,
price_per_gb: NumberDecimal("0.25")
},
binary_data: BinData(0, "aGVsbG8="), // Base64 "hello"
location: {
type: "Point",
coordinates: [-73.97, 40.77]
},
checksum: UUID("b5c1c6a0-7e93-4a8e-9c3d-1f2b4c5d6e7f")
}