
mongodb
安装:https://software.share888.top/note/devtool/detail/MongoDB.html
常用的命令
示例数据(假设集合名为 users)
注意,db这个是写死的,mongodb里面就是这样查询的
批量新增
sql
db.users.insertMany([
{ name: "Alice", age: 25, city: "Beijing", active: true },
{ name: "Bob", age: 30, city: "Shanghai", active: true },
{ name: "Charlie", age: 35, city: "Beijing", active: false },
{ name: "David", age: 25, city: "Guangzhou", active: true }
])查询
根据_id查询
注意;_id 是mongodb自动生成的字段。
sql
db.集合名.find({ "_id": ObjectId("67373e393b63f79377fa6232") })查询所有
sql
db.users.find()多条件查询(AND)
sql
-- 查询 age 等于 25 的用户
db.users.find({ age: 25 })
-- 返回 age=25 且 city="Beijing" 的用户(Alice)
db.users.find({ age: 25, city: "Beijing" })范围查询
sql
-- 返回 age 大于 25 的用户(Bob 和 Charlie)
db.users.find({ age: { $gt: 25 } })
-- 查询 age 在 [25, 30] 范围内(>=25 且 <=30)
db.users.find({ age: { $gte: 25, $lte: 30 } })
-- 查询 city 在 ["Beijing", "Shanghai"] 中的用户
db.users.find({ city: { $in: ["Beijing", "Shanghai"] } })正则表达式查询
sql
-- 使用正则表达式查询 name 包含 "A" 或 "a" 的用户
db.users.find({ name: /a/i })查询某个字段不存在的文档
sql
-- 返回没有 email 字段的文档。
db.users.find({ email: { $exists: false } })or查询
sql
//select * from users where (age>=20 and age <=30) and (name = "Alice" or id = "D")
db.users.aggregate([
{
$match: {
age: {
$gte: 20,
$lte: 30
},
$or: [
{
name: "Alice"
},
{
id: "D"
},
]
}
}
])其他场景
必须存在某字段
sql
-- 这条命令会返回所有 email 字段存在的文档,无论该字段的值是什么(包括 null)
db.users.find({ "email": { $exists: true } })
-- 如果你想查找 email 字段存在且不为 null 的文档,可以结合 $ne 操作符
db.users.find({"email": { $exists: true, $ne: null }})显示指定字段
sql
-- 只返回 name 和 city 字段,不返回 _id。
db.users.find({}, { name: 1, city: 1, _id: 0 })
-- 查询 active 为 true 的用户,并只显示 name
db.users.find({ active: true }, { name: 1, _id: 0 })分页
sql
db.users.find().limit(2)排序
使用 .sort() 排序(1: 升序,-1: 降序)
sql
db.users.find().sort({ age: 1 })组合使用
sql
db.users.find({ active: true }).sort({ age: -1 }).limit(3)distinct count统计
sql
db.users.aggregate([
{
$group: {
_id: "$id" // 按 id 字段分组,自动去重
}
},
{
$count: "unique_id_count" // 统计去重后的数量
}
])也可以加上其他限制条件
sql
db.users.aggregate([
{
$match: {
age: {
$gte: 20,
$lte: 30
},
sex : "Male"
}
},
{
$group: {
_id: "$id" // 按 id 字段分组,自动去重
}
},
{
$count: "unique_id_count" // 统计去重后的数量
}
])分组
准备数据
sql
db.users.insertMany([
{
"id": "A",
"name": "Alice",
"sex": "Female",
"age": 28,
"address": "123 Maple Street, New York, NY",
"email": "alice@example.com",
"phone": "+1-555-1001"
},
{
"id": "B",
"name": "Bob",
"sex": "Male",
"age": 34,
"address": "456 Oak Avenue, Los Angeles, CA",
"email": "bob@example.com",
"phone": "+1-555-1002"
},
{
"id": "A",
"name": "Anna",
"sex": "Female",
"age": 25,
"address": "789 Pine Road, Chicago, IL",
"email": "anna@example.com",
"phone": "+1-555-1003"
},
{
"id": "C",
"name": "Charlie",
"sex": "Male",
"age": 41,
"address": "321 Elm Boulevard, Houston, TX",
"email": "charlie@example.com",
"phone": "+1-555-1004"
},
{
"id": "B",
"name": "Brian",
"sex": "Male",
"age": 30,
"address": "654 Cedar Lane, Phoenix, AZ",
"email": "brian@example.com",
"phone": "+1-555-1005"
},
{
"id": "D",
"name": "Diana",
"sex": "Female",
"age": 29,
"address": "987 Willow Drive, Philadelphia, PA",
"email": "diana@example.com",
"phone": "+1-555-1006"
},
{
"id": "E",
"name": "Evan",
"sex": "Male",
"age": 36,
"address": "147 Spruce Court, San Antonio, TX",
"email": "evan@example.com",
"phone": "+1-555-1007"
},
{
"id": "F",
"name": "Fiona",
"sex": "Female",
"age": 27,
"address": "258 Birch Street, San Diego, CA",
"email": "fiona@example.com",
"phone": "+1-555-1008"
},
{
"id": "G",
"name": "George",
"sex": "Male",
"age": 45,
"address": "369 Sycamore Place, Dallas, TX",
"email": "george@example.com",
"phone": "+1-555-1009"
},
{
"id": "H",
"name": "Hannah",
"sex": "Female",
"age": 22,
"address": "135 Ash Lane, San Jose, CA",
"email": "hannah@example.com",
"phone": "+1-555-1010"
}
]);group by having
注意,默认分组的字段名叫_id,如果想自定义的话,需要再设置下
sql
db.users.aggregate([
// Step 1: 先按 id 降序排序
{ $sort: { id: -1 } },
// Step 2: 按 id 分组,并按排序后的顺序 push
{
$group: {
_id: "$id",
_ids: { $push: "$_id" }, // ✅ 收集所有 MongoDB 文档的 name
names: { $push: "$name" }, // ✅ 收集所有 MongoDB 文档的 name
sexs: { $addToSet: "$sex" }, // ✅ 收集所有 MongoDB 文档的 sex
count: { $sum: 1 }
}
},
// Step 3: 筛选出重复的记录
{
$match: {
count: { $gt: 1 }
}
},
// Step 4: 投影输出字段
{
$project: {
_id: 0, // 可选:删除分组键的 _id
id: "$_id", // 把分组键重命名为字段 "id"
_ids:1, // ✅ 关键:把收集的 MongoDB _id 列表也输出!
count: 1,
names: 1, // ✅ 关键:把收集的 MongoDB name 列表也输出!
sexs: 1 // ✅ 关键:把收集的 MongoDB sex 列表也输出!
}
}
]).forEach(function(doc) {
var idsToDelete = doc._ids.slice(1); // 跳过第一个,保留它
if (idsToDelete.length > 0) {
// 🔹 打印调试信息
print("正在处理重复 id:", doc.id);
print("总共找到重复文档:", doc.count, "条");
print("将删除以下 _id:", JSON.stringify(idsToDelete));
// 执行删除
var result = db.users.deleteMany({ _id: { $in: idsToDelete } });
// 打印删除结果
print("成功删除:", result.deletedCount, "条文档\n");
}
})注意,如果是数据量很大的情况下,mongodb会报错,需要加个参数。
- $group 阶段需要在内存中维护分组状态(比如每个分组的累计值)
- 默认情况下,MongoDB 只允许使用 100MB 内存 来执行聚合操作
- 如果你的数据量大、分组多,很容易超过这个限制
- 当内存不足时,MongoDB 需要“使用磁盘”来辅助排序/分组(称为 external sort / external aggregation)
- 但默认是禁用的,必须显式开启:allowDiskUse: true
sql
db.users.aggregate([/* 你的条件 */], { allowDiskUse: true })索引
查看当前索引
sql
db.users.getIndexes()分析sql语句
sql
db.users.find({ id: "valid_id" }).explain("executionStats")核心判断标准:查看 stage 字段
最关键的指标在 executionStats.executionStages.stage 和 queryPlanner.winningPlan.stage 这两个地方。
sql
"executionStages": {
"stage": "COLLSCAN", // 👈 关键!
...
},
"winningPlan": {
"stage": "COLLSCAN", // 👈 关键!
...
}- COLLSCAN:表示 Collection Scan,即全集合扫描。MongoDB 扫描了整个集合来查找匹配的文档。
- 理想情况:如果命中了索引,这里应该是 IXSCAN (Index Scan)。
其他关键指标分析
totalKeysExamined: 0- 含义:检查的索引键数量。
- 分析:
0表示没有使用任何索引。如果使用了索引,这个值会大于 0。
totalDocsExamined: 8- 含义:检查的文档数量。
- 分析:
8表示 MongoDB 扫描了集合中的全部 8 条文档。这与COLLSCAN一致。
nReturned: 0- 含义:返回的文档数量。
- 分析:
0表示没有找到id等于"valid_id"的文档。这与您的查询意图相符。
executionTimeMillis: 0- 含义:执行时间(毫秒)。
- 分析:
0表示查询非常快,但这仅仅是因为集合很小(只有 8 条数据)。如果集合有 10 万条数据,COLLSCAN会非常慢。
创建索引
第一种方式
sql
// 为 users 集合的 id 字段创建升序索引
db.users.createIndex({ "id": 1 }, { unique: true })第二种方式
sql
db.runCommand({
createIndexes: "users",
indexes: [
{
key: { "id": 1 },
name: "uk_id", // 可选:自定义索引名
unique: true
}
]
})删除索引
sql
db.collection.dropIndex("索引名称")
db.collection.dropIndexes()
db.collection.dropIndexes(["索引名1", "索引名2"])
