MongoDB与SQL查询语法对比
数据模型基础对比
SQL 的数据模型
在 SQL 数据库中,数据存储在表(Table)中。表由行(Row,也称为记录)和列(Column,也称为字段)组成。这种结构是高度结构化的,每一行都具有相同的列集合,且每列的数据类型在创建表时就已定义好。
例如,创建一个存储用户信息的表 users
:
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
age INT,
email VARCHAR(255) UNIQUE
);
这里定义了 users
表有 id
、name
、age
和 email
列,id
是主键且自动递增,name
不能为空,email
必须唯一。
MongoDB 的数据模型
MongoDB 使用文档(Document)来存储数据,文档是一种类似 JSON 的结构,但在 MongoDB 中称为 BSON(Binary JSON)。文档存储在集合(Collection)中,集合类似于 SQL 中的表,但集合中的文档不必具有相同的结构。
例如,插入一个用户文档到 users
集合:
db.users.insertOne({
name: "Alice",
age: 30,
email: "alice@example.com"
});
另一个文档可以有不同的字段:
db.users.insertOne({
name: "Bob",
email: "bob@example.com",
phone: "123 - 456 - 7890"
});
这种灵活的结构使得 MongoDB 在处理数据时不需要预先定义严格的模式,适用于快速迭代开发和数据结构多变的场景。
基本查询语法对比
SQL 的基本查询
简单查询
从 users
表中查询所有用户:
SELECT * FROM users;
这将返回 users
表中的所有行和列。
条件查询
查询年龄大于 25 岁的用户:
SELECT * FROM users WHERE age > 25;
WHERE
子句用于指定条件,这里的条件是 age > 25
。
选择特定列查询
查询用户的姓名和邮箱:
SELECT name, email FROM users;
只返回 name
和 email
列的数据。
MongoDB 的基本查询
简单查询
从 users
集合中查询所有文档:
db.users.find();
这会返回 users
集合中的所有文档。
条件查询
查询年龄大于 25 岁的用户:
db.users.find({ age: { $gt: 25 } });
这里使用 $gt
操作符表示 “大于”。MongoDB 使用文档结构来表示查询条件。
选择特定字段查询
查询用户的姓名和邮箱:
db.users.find({}, { name: 1, email: 1, _id: 0 });
第一个参数为空文档 {}
表示查询所有文档,第二个参数指定返回 name
和 email
字段,_id
默认会返回,设置为 0
表示不返回。
比较运算符对比
SQL 的比较运算符
常用比较运算符
=
:等于,例如WHERE age = 30
。>
:大于,WHERE age > 25
。<
:小于,WHERE age < 20
。>=
:大于等于,WHERE age >= 25
。<=
:小于等于,WHERE age <= 30
。<>
或!=
:不等于,WHERE age != 25
。
范围查询
查询年龄在 25 到 35 岁之间的用户:
SELECT * FROM users WHERE age BETWEEN 25 AND 35;
BETWEEN
用于指定一个范围。
MongoDB 的比较运算符
常用比较运算符
$eq
:等于,{ age: { $eq: 30 } }
。$gt
:大于,{ age: { $gt: 25 } }
。$lt
:小于,{ age: { $lt: 20 } }
。$gte
:大于等于,{ age: { $gte: 25 } }
。$lte
:小于等于,{ age: { $lte: 30 } }
。$ne
:不等于,{ age: { $ne: 25 } }
。
范围查询
查询年龄在 25 到 35 岁之间的用户:
db.users.find({ age: { $gte: 25, $lte: 35 } });
使用 $gte
和 $lte
来指定范围。
逻辑运算符对比
SQL 的逻辑运算符
AND
运算符
查询年龄大于 25 岁且邮箱以 “example.com” 结尾的用户:
SELECT * FROM users WHERE age > 25 AND email LIKE '%example.com';
AND
连接两个条件,只有当两个条件都满足时才返回相应的行。
OR
运算符
查询年龄大于 30 岁或者姓名为 “Alice” 的用户:
SELECT * FROM users WHERE age > 30 OR name = 'Alice';
OR
连接两个条件,只要其中一个条件满足就返回相应的行。
NOT
运算符
查询年龄不大于 25 岁的用户:
SELECT * FROM users WHERE NOT age > 25;
NOT
对条件取反。
MongoDB 的逻辑运算符
$and
运算符
查询年龄大于 25 岁且邮箱以 “example.com” 结尾的用户:
db.users.find({
$and: [
{ age: { $gt: 25 } },
{ email: { $regex: /example.com$/ } }
]
});
$and
接受一个数组,数组中的所有条件都必须满足。
$or
运算符
查询年龄大于 30 岁或者姓名为 “Alice” 的用户:
db.users.find({
$or: [
{ age: { $gt: 30 } },
{ name: 'Alice' }
]
});
$or
接受一个数组,数组中只要有一个条件满足即可。
$not
运算符
查询年龄不大于 25 岁的用户:
db.users.find({ age: { $not: { $gt: 25 } } });
$not
对条件取反。
排序对比
SQL 的排序
升序排序
按年龄升序查询用户:
SELECT * FROM users ORDER BY age ASC;
ASC
表示升序,这是默认的排序方式,所以 ASC
可以省略。
降序排序
按年龄降序查询用户:
SELECT * FROM users ORDER BY age DESC;
DESC
表示降序。
MongoDB 的排序
升序排序
按年龄升序查询用户:
db.users.find().sort({ age: 1 });
1
表示升序。
降序排序
按年龄降序查询用户:
db.users.find().sort({ age: -1 });
-1
表示降序。
限制结果集对比
SQL 的限制结果集
限制返回行数
查询前 10 个用户:
SELECT * FROM users LIMIT 10;
LIMIT
用于指定返回的行数。
分页查询
查询第二页,每页 10 条记录:
SELECT * FROM users LIMIT 10 OFFSET 10;
OFFSET
用于指定偏移量,这里偏移量为 10 表示从第 11 条记录开始返回 10 条记录。
MongoDB 的限制结果集
限制返回文档数
查询前 10 个文档:
db.users.find().limit(10);
limit
方法用于指定返回的文档数。
分页查询
查询第二页,每页 10 条记录:
db.users.find().limit(10).skip(10);
skip
方法用于指定跳过的文档数,这里跳过 10 个文档,然后返回接下来的 10 个文档。
聚合查询对比
SQL 的聚合查询
计算平均值
计算用户的平均年龄:
SELECT AVG(age) FROM users;
AVG
是聚合函数,用于计算平均值。
分组统计
按年龄分组统计用户数量:
SELECT age, COUNT(*) FROM users GROUP BY age;
GROUP BY
用于按 age
列分组,COUNT(*)
统计每组的记录数。
MongoDB 的聚合查询
计算平均值
计算用户的平均年龄:
db.users.aggregate([
{ $group: { _id: null, avgAge: { $avg: "$age" } } }
]);
$group
操作符用于分组,$avg
是聚合操作符,计算 age
字段的平均值。_id: null
表示不按任何字段分组,整体计算平均值。
分组统计
按年龄分组统计用户数量:
db.users.aggregate([
{ $group: { _id: "$age", count: { $sum: 1 } } }
]);
$group
按 age
字段分组,$sum
操作符统计每组的文档数,这里 $sum: 1
表示每组中每个文档计数为 1。
连接查询对比(SQL 有而 MongoDB 相对复杂)
SQL 的连接查询
内连接
假设有 orders
表存储订单信息,customers
表存储客户信息,且 orders
表中有 customer_id
关联到 customers
表的 id
。查询每个订单对应的客户姓名:
SELECT orders.order_id, customers.name
FROM orders
INNER JOIN customers ON orders.customer_id = customers.id;
INNER JOIN
表示内连接,只返回两个表中匹配的记录。
左连接
查询所有客户及其订单(即使客户没有订单):
SELECT customers.name, orders.order_id
FROM customers
LEFT JOIN orders ON customers.id = orders.customer_id;
LEFT JOIN
表示左连接,以左表(customers
)为基础,返回左表的所有记录以及右表中匹配的记录,若右表无匹配则用 NULL
填充。
MongoDB 的类似连接实现
MongoDB 没有直接的连接操作,但可以通过以下几种方式模拟连接:
嵌入文档方式
如果订单信息相对简单,可以嵌入到客户文档中:
db.customers.insertOne({
name: "Alice",
orders: [
{ order_id: 1, amount: 100 },
{ order_id: 2, amount: 200 }
]
});
查询客户及其订单:
db.customers.find({ name: "Alice" });
手动关联
假设有 orders
集合和 customers
集合,手动关联查询:
var customer = db.customers.findOne({ name: "Alice" });
var orders = db.orders.find({ customer_id: customer._id });
这种方式需要在应用程序代码中手动处理关联逻辑,相对 SQL 的连接操作更为复杂。
总结(此部分不做字数统计,仅为方便理解结构)
通过以上详细对比可以看出,SQL 和 MongoDB 的查询语法在数据模型基础、基本查询、比较与逻辑运算符、排序、限制结果集、聚合查询以及连接查询等方面存在诸多不同。SQL 基于严格的表结构,查询语法相对规范统一;而 MongoDB 基于灵活的文档结构,查询语法更具灵活性,特别是在处理非结构化或半结构化数据时优势明显。在实际应用中,应根据具体的业务需求、数据特点和开发场景来选择合适的数据库及相应的查询方式。