新手入门MongoDB

327 阅读6分钟

简介

Mongo和Mysql对比

image.png image.png

使用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: { $gt25 } },  
    { name1, age1, _id0 }  
);

db.myCollection.findOne({ name: "Alice" });

MongoDB 查询操作符与 MySQL 语法对照表

操作类别与说明MongoDB 操作符示例与等价语法
比较操作符
等于 - 精确匹配$eqMongoDB: db.users.find({ age: { $eq: 25 } })
MySQL: SELECT * FROM users WHERE age = 25
不等于$neMongoDB: db.users.find({ status: { $ne: "inactive" } })
MySQL: SELECT * FROM users WHERE status <> 'inactive'
大于$gtMongoDB: db.products.find({ price: { $gt: 100 } })
MySQL: SELECT * FROM products WHERE price > 100
大于等于$gteMongoDB: db.orders.find({ total: { $gte: 50 } })
MySQL: SELECT * FROM orders WHERE total >= 50
小于$ltMongoDB: db.students.find({ score: { $lt: 60 } })
MySQL: SELECT * FROM students WHERE score < 60
小于等于$lteMongoDB: db.employees.find({ level: { $lte: 3 } })
MySQL: SELECT * FROM employees WHERE level <= 3
逻辑操作符
与 - 多条件同时满足$andMongoDB: db.users.find({ $and: [ { age: { $gt: 18 } }, { status: "active" } ] })
MySQL: SELECT * FROM users WHERE age > 18 AND status = 'active'
或 - 任一条件满足$orMongoDB: db.products.find({ $or: [ { category: "book" }, { price: { $lt: 20 } } ] })
MySQL: SELECT * FROM products WHERE category = 'book' OR price < 20
非 - 取反操作$notMongoDB: db.customers.find({ age: { $not: { $gt: 30 } } })
MySQL: SELECT * FROM customers WHERE NOT age > 30
或非 - 所有条件都不满足$norMongoDB: db.logs.find({ $nor: [ { type: "error" }, { priority: { $gte: 5 } } ] })
MySQL: SELECT * FROM logs WHERE NOT (type = 'error' OR priority >= 5)
元素操作符
字段存在 - 检查字段是否存在$existsMongoDB: db.users.find({ phone: { $exists: true } })
MySQL: SELECT * FROM users WHERE phone IS NOT NULL
字段类型 - 按BSON类型查询$typeMongoDB: db.data.find({ value: { $type: "decimal" } })
MySQL: SELECT * FROM data WHERE JSON_TYPE(value) = 'DECIMAL'
数组操作符
包含所有元素 - 数组包含指定所有元素$allMongoDB: db.products.find({ tags: { $all: ["sale", "new"] } })
MySQL: SELECT * FROM products WHERE JSON_CONTAINS(tags, '["sale","new"]')
数组长度 - 按数组长度查询$sizeMongoDB: db.orders.find({ items: { $size: 3 } })
MySQL: SELECT * FROM orders WHERE JSON_LENGTH(items) = 3
元素匹配 - 数组元素同时满足多个条件$elemMatchMongoDB: 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)
评估操作符
正则表达式 - 模式匹配$regexMongoDB: db.users.find({ name: { $regex: /^ali/i } })
MySQL: SELECT * FROM users WHERE name REGEXP '^ali'
全文搜索 - 文本索引搜索$textMongoDB: db.articles.find({ $text: { $search: "database -mongodb" } })
MySQL: SELECT * FROM articles WHERE MATCH(content) AGAINST('+database -mongodb' IN BOOLEAN MODE)
聚合表达式 - 使用聚合表达式查询$exprMongoDB: 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: 无直接等价(需应用层处理)
数组切片 - 返回数组的子集$sliceMongoDB: db.posts.find({}, { comments: { $slice: 5 } })
MySQL: SELECT id, JSON_EXTRACT(comments, '$[0 to 4]') AS comments FROM posts
地理空间操作符
地理范围内 - 多边形内点查询$geoWithinMongoDB: db.places.find({ loc: { $geoWithin: { $geometry: { type: "Polygon", coordinates: [...] } } } })
MySQL: SELECT * FROM places WHERE ST_Within(loc, ST_GeomFromText('POLYGON(...)'))
邻近点 - 按距离排序查询$nearMongoDB: 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

特殊查询操作符详解

  • 嵌套文档查询
操作MongoDBMySQL
精确匹配嵌套文档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'
  • 数组元素查询
操作MongoDBMySQL
索引位置匹配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'
  • 分页与排序操作
操作MongoDBMySQL
排序// 按 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 类型更强大。以下是所有数据类型的详细说明和示例:

一、基础数据类型

类型常量标识符说明示例
StringstringUTF-8 字符串{ "name": "Alice" }
Integerint32 位或 64 位整数(自动判定){ "age": 30 }
Doubledouble双精度浮点数{ "price": 19.99 }
Booleanbool布尔值{ "is_active": true }
Nullnull空值{ "description": null }

二、特殊数值类型

类型常量标识符说明示例
NumberIntint强制 32 位整数{ "count": NumberInt(50) }
NumberLonglong强制 64 位整数{ "population": NumberLong(10000000000) }
NumberDecimaldecimal高精度小数(金融计算){ "total": NumberDecimal("100.5000") }

三、日期与时间

类型说明示例
DateUTC 日期时间(毫秒精度){ "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" } })
  • 类型标识符对照表
类型名数字标识符字符串标识符
Double1"double"
String2"string"
Object3"object"
Array4"array"
BinData5"binData"
ObjectId7"objectId"
Boolean8"bool"
Date9"date"
Null10"null"
Regular Expression11"regex"
32-bit Integer16"int"
Timestamp17"timestamp"
64-bit Integer18"long"
Decimal12819"decimal"
MinKey-1"minKey"
MaxKey127"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")
}