MongoDB系列教程-第二章:MongoDB数据库概念和特点、数据库操作、集合操作、文档操作、规范及常见问题解决、实际应用示例

发布于:2025-07-31 ⋅ 阅读:(16) ⋅ 点赞:(0)

📖 第二章:MongoDB数据库概念和特点、数据库操作、集合操作、文档操作、规范及常见问题解决、实际应用示例

2.1 数据库概念及MongoDB数据库的特点

数据库就像一个巨大的文件柜,里面有很多抽屉(数据库),每个抽屉里有很多文件夹(集合),文件夹里存放着各种文件(文档)。在MongoDB中,数据库就是用来组织和存储相关数据的容器。

MongoDB数据库的特点

  1. 自动创建
    MongoDB有一个非常方便的特性:当你第一次向一个不存在的数据库插入数据时,它会自动创建这个数据库。这就像你第一次往一个新抽屉里放东西时,抽屉会自动出现一样。

  2. 无需预定义结构
    与传统数据库不同,MongoDB不需要预先定义表结构,你可以随时添加新的字段,就像在文件夹里随时添加新的文件一样。


2.2 MongoDB数据库操作指令

  • use :指定某个数据库(该数据库不存在,MongoDB将自动创建它)。
  • show dbs:查看所有数据库。
  • db:查看当前数据库。
  • db.stats():查看数据库统计信息。
  • db.getName():查看数据库名称。
  • db.runCommand({dbStats: 1, scale: 1024}) :查看数据库大小,以KB为单位。
  • db.copyDatabase("source_db", "target_db", "localhost:27017"):复制数据库:source_db(源数据库)→ target_db(目标数据库)。
    • 第一个参数 “source_db”:源数据库名称(要复制的数据库)。
    • 第二个参数 “target_db”:目标数据库名称(复制后生成的新数据库)。
    • 第三个参数 “localhost:27017”:源数据库所在的服务器地址(这里是本地默认端口,若源数据库在远程服务器,需填写 ip:port)。
    • 执行后,MongoDB 会将 "source_db “中的所有集合、文档、索引完整复制到"target_db”,两个数据库成为独立副本(后续修改源数据库不会影响目标数据库)。
    • 若 “target_db” 已存在,复制会失败,需先删除目标数据库或更换名称。
    • 适合快速创建测试环境副本、临时备份小型数据库,不建议用于超大型数据库(可能导致性能下降)。
  • db.dropDatabase():删除当前数据库(包含所有集合),删除后常使用show dbs来验证删除。
  • 数据库维护,示例:
// 修复数据库
use myapp
db.repairDatabase()

// 验证数据库
db.runCommand({validate: "users"})

// 压缩数据库
db.runCommand({compact: "users"})

2.3 MongoDB集合操作指令

指定数据库之后,针对集合操作:

  • show collections:查看当前数据库的所有集合,或者使用show tables
  • db.集合名字.stats():查看集合统计。
  • db.集合名字.insertOne():向数据库指定名字的集合中插入一条数据(文档),如果没有这个集合的话插入数据的时候会自动创建,其中的db.集合名字表示当前数据库中的指定名字的那个集合。
    • 常见的db.admins.insertOne()中的users 只是一个常见的集合命名(用于存储普通用户数据)。
    • 想存储管理员用户,可以命名集合为 admins,即使用db.admins.insertOne()
    • 再比如,存储第三方登录用户,可以命名为 oauth_users,即使用db.oauth_users.insertOne()
  • db.集合名字.insertMany():向数据库指定名字的集合中插入多条数据(文档),没有集合会自动创建。
  • db.集合名字.find():查看集合中的数据。
  • db.集合名字.drop() :删除指定集合名字的集合,.drop() 是删除集合的核心方法,执行后集合的所有数据(文档、索引)会被永久删除,释放磁盘空间。删除集合需注意:
    • 使用之前必须确定清楚集合所在的数据库并使用use切换进去,再删除,否则会默认操作当前数据库,可能导致找不到目标集合。
    • 不可逆性:删除集合后,其中的文档和索引无法恢复,建议操作前备份重要数据。
    • 权限要求:执行删除操作的用户需具备集合的 drop 权限(通常是数据库的 readWrite 或更高权限)。
    • 返回值含义:返回 true 表示删除成功;返回 false 通常是因为集合不存在或无权限。
  • db.createCollection("集合名字"):显式创建集合。
  • db.createCollection(name, options):创建带选项的集合。
    • name:字符串,必选,指定集合名称。
    • options:对象,可选,配置集合的特殊属性。例如可以指定cappedsizemaxautoIndexIdvalidator等参数。MongoDB 中 db.createCollection() 方法的所有常用配置参数,汇总如下:
参数名 类型 描述 示例值
capped 布尔值 是否创建固定大小集合(容量满后自动覆盖最旧数据) true
size 数值 固定集合的最大存储空间(字节),仅当 capped: true 时有效且为必填项 10485760(10MB)
max 数值 固定集合允许的最大文档数量,仅当 capped: true 时有效(与 size 冲突时,以先达到的条件为准) 5000
autoIndexId 布尔值 是否自动为 _id 字段创建索引(默认值为 true,不建议关闭,可能影响查询性能) false
validator 对象 定义文档插入/更新时的验证规则(使用 MongoDB 查询操作符),不符合规则的操作将受 validationAction 控制 { $jsonSchema: { required: ["username", "email"] } }
validationLevel 字符串 指定文档验证的严格程度:
- off:不进行任何验证
- strict:对所有插入和更新操作进行验证(默认值)
- moderate:仅对新插入文档和修改过的现有文档进行验证
"moderate"
validationAction 字符串 指定验证失败时的处理行为:
- error:阻止不符合规则的插入/更新操作(默认值)
- warn:允许操作,但记录警告日志
"warn"
storageEngine 对象 为集合指定存储引擎配置(需数据库支持多存储引擎),可针对不同引擎设置特定参数(如压缩算法) { wiredTiger: { configString: "block_compressor=zstd" } }
collation 对象 定义集合的默认排序规则,包括语言、大小写敏感性、重音符号处理等 { locale: "zh", strength: 2, caseLevel: false }(中文,忽略大小写)
timeseries 对象 创建时间序列集合(优化时序数据存储,如监控指标、传感器数据),必选 timeField(存储时间戳的字段名),可选 metaField(元数据字段)和 granularity(数据粒度:seconds/minutes/hours { timeField: "timestamp", metaField: "deviceId", granularity: "hours" }
expireAfterSeconds 数值 文档自动过期时间(秒),需配合日期字段的索引使用(文档会在指定时间后被自动删除) 86400(24小时后过期)
viewOn 字符串 创建视图(基于其他集合的虚拟集合)时,指定源集合的名称,需与 pipeline 配合使用 "rawData"
pipeline 数组 创建视图时的聚合管道,定义视图数据的筛选、转换或计算规则(由聚合操作符组成) [{ $match: { status: "active" } }, { $project: { name: 1, value: 1 } }]

参数说明:

  1. capped: true
    • 核心开关:设置为 true 时,集合成为固定大小集合(容量和数量受限,满了会自动覆盖旧数据)。
    • 固定集合的特性:
      • 容量固定,写入顺序严格按照插入顺序(类似日志文件的 “先进先出”)。
      • 不支持删除单个文档(只能清空整个集合),也不允许修改文档大小(避免破坏存储结构)。
      • 读取效率极高,适合存储日志、监控数据等按时间顺序写入和查询的场景。
  2. size: 100000
    • 单位:字节(Byte),此处 100000 表示 100KB。
    • 作用:限制集合的最大存储空间。当集合占用的磁盘空间达到 100KB 时,新写入的文档会自动覆盖最旧的文档。
    • 注意:size 是固定集合 capped为true)的必选参数(即使设置了 max,也必须指定 size)。
  3. max: 1000
    • 单位:文档数量,此处表示最多存储 1000 个文档。
    • 作用:限制集合能存储的最大文档数量。当文档数量达到 1000 个时,新写入的文档会自动覆盖最旧的文档。
    • 优先级:sizemax 同时设置时,哪个条件先满足就触发覆盖(例如,若 1000 个文档的总大小未达 100KB,则按数量限制;若未到 1000 个文档但总大小达 100KB,则按空间限制)。
  4. autoIndexId(索引相关)
    • 类型:布尔值(默认 true)。
    • 作用:是否自动为 _id 字段创建索引。
    • 示例:{ autoIndexId: false } 表示不自动创建 _id 索引(不推荐,可能影响查询效率)。
  5. validator(验证规则(数据校验))
    • 类型:文档(查询表达式)。
    • 作用:定义文档插入 / 更新时的验证规则,不符合规则的操作会被拒绝。
    • 示例:要求插入的文档必须包含 email 字段且格式符合邮箱规则:
db.createCollection("users", {
  validator: {
    $and: [
      { email: { $exists: true } },  // 必须存在email字段
      { email: { $regex: /@/ } }     // email格式需包含@
    ]
  }
})
  1. validationLevel
    • 类型:字符串(默认 strict)。
    • 作用:指定验证严格程度:
      • strict:对所有插入 / 更新操作进行验证(默认)。
      • moderate:仅对新插入的文档和修改过的现有文档进行验证。
  2. validationAction
    • 类型:字符串(默认 error)。
    • 作用:验证失败时的处理方式:
      • error:直接拒绝不符合规则的操作(默认)。
      • warn:允许操作,但记录警告日志。
  3. storageEngine
    • 类型:文档。
    • 作用:为集合指定特定的存储引擎配置(需数据库支持多存储引擎)。
    • 示例:为集合指定 WiredTiger 存储引擎的压缩方式:
db.createCollection("largeData", {
  storageEngine: {
    wiredTiger: {
      configString: "block_compressor=zstd"  // 使用zstd压缩算法
    }
  }
})
  1. collation
    • 类型:文档。
    • 作用:定义集合的排序规则(如语言、大小写敏感性)。
    • 示例:创建一个不区分大小写的集合:
db.createCollection("products", {
  collation: {
    locale: "en",
    strength: 2  // 1=忽略大小写和重音,2=忽略大小写(保留重音)
  }
})
  1. timeseries
    • 类型:文档。
    • 作用:创建时间序列集合(专门优化用于存储时序数据,如监控指标、传感器数据)。
    • 必选子参数:
      • timeField:指定存储时间戳的字段名(如 timestamp)。
    • 示例:
db.createCollection("sensorData", {
  timeseries: {
    timeField: "timestamp",  // 时间戳字段
    metaField: "deviceId",   // 元数据字段(如设备ID,用于分组)
    granularity: "minutes"   // 数据粒度(优化查询性能)
  }
})
  1. expireAfterSeconds
    • 类型:数字。
    • 作用:为集合中的文档设置自动过期时间(需配合 _id 以外的日期字段使用)。
    • 示例:文档在 createdAt 字段指定的时间后 3600 秒(1 小时)自动删除:
db.createCollection("tempData", { expireAfterSeconds: 3600 })
// 需手动为createdAt字段创建索引:
db.tempData.createIndex({ createdAt: 1 })
  1. viewOn
    • 类型:字符串。
    • 作用:创建视图(基于其他集合的虚拟集合,不存储实际数据,仅展示源集合经处理后的结果)时,用于指定源集合的名称。必须与 pipeline 参数配合使用,否则无法创建视图。
    • 示例:基于 orders 集合创建视图:
db.createCollection("activeOrdersView", {
  viewOn: "orders",  // 源集合为orders
  pipeline: [{ $match: { status: "active" } }]  // 配合pipeline定义视图规则
})
  1. pipeline
    • 类型:数组(由聚合操作符组成)。
    • 作用:创建视图时,定义对源集合数据的筛选、转换、计算等规则(即聚合管道),视图将展示经过管道处理后的结果。需与 viewOn 参数配合使用。
    • 示例:从 orders 集合中筛选出状态为“completed”的文档,并只展示 orderIdtotalAmount 字段:
db.createCollection("completedOrdersView", {
  viewOn: "orders",
  pipeline: [
    { $match: { status: "completed" } },  // 筛选状态为completed的文档
    { $project: { orderId: 1, totalAmount: 1, _id: 0 } }  // 只保留指定字段
  ]
})
// 视图completedOrdersView将只显示符合条件的文档及指定字段
  • (续上述集合操作)更新集合名
    在 MongoDB 中,重命名集合主要有两种方法:

    • 方法一:通过 db.adminCommand() 执行 renameCollection 命令

      1. 适用场景:适用于所有 MongoDB 环境(包括 shell 命令行、驱动程序调用),是通用性较强的官方推荐方式。
      2. 语法格式
        db.adminCommand({
          renameCollection: "<旧集合完整名称>",  // 必选,格式为 "数据库名.集合名"(需包含所属数据库)
          to: "<新集合完整名称>",                // 必选,格式同上(新集合的数据库可以与旧集合不同,实现跨库移动)
          dropTarget: <布尔值>                  // 可选,默认 false;若新集合已存在,true 表示删除旧的新集合后重命名,false 表示不删除(此时会报错)
        })
        
      3. 示例
        • test 数据库中的 users 集合重命名为 customers(同库重命名):
          db.adminCommand({ renameCollection: "test.users", to: "test.customers" })
          
        • test 数据库的 users 移动到 newdb 数据库并命名为 clients(跨库移动+重命名):
          db.adminCommand({ renameCollection: "test.users", to: "newdb.clients" })
          
    • 方法二:直接调用数据库对象的 renameCollection() 方法

      1. 适用场景:主要用于 MongoDB shell 环境或支持该方法的驱动程序,操作更简洁,但功能相对单一。
      2. 语法格式
        // 先切换到集合所属的数据库
        use 数据库名
        // 调用 renameCollection 方法
        db.renameCollection("<旧集合名>", "<新集合名>", <dropTarget>)
        
        • 参数说明:
          • <旧集合名>:必选,仅需集合名(无需带数据库,因已通过 use 切换到目标库)。
          • <新集合名>:必选,仅需集合名(新集合会被创建在当前数据库中,不支持跨库操作)。
          • <dropTarget>:可选,布尔值,默认 false(作用同方法一)。
      3. 示例
        test 数据库中的 users 集合重命名为 customers(同库操作):
        use test  // 切换到 test 数据库
        db.renameCollection("users", "customers")  // 重命名当前库下的集合
        
        
    • 两种方法的核心区别

    对比项 方法一(db.adminCommand 方法二(db.renameCollection
    跨库操作 支持(可将集合移动到其他数据库) 不支持(只能在当前数据库内重命名)
    集合名称格式 需带数据库名(如 test.users 仅需集合名(依赖 use 切换的数据库)
    适用环境 所有环境(shell、驱动程序) 主要用于 shell 或特定驱动
    • 更新集合名,需要注意:
      1. 重命名操作会临时锁定源集合,期间无法写入数据,建议在低峰期执行。
      2. 若新集合已存在且 dropTargetfalse,两种方法都会报错(需手动删除旧的新集合或设置 dropTarget: true)。
      3. 【重要】执行用户需具备 renameCollection 权限(通常为数据库管理员权限)。

2.4 MongoDB文档操作指令

文档的数据结构和 JSON 基本一样。所有存储在集合中的数据都是 BSON 格式(Binary JSON 的简称)。
指定数据库和集合之后,针对文档(数据记录)的操作:

  • db.集合名字.insertOne(document):向集合中插入单条文档

    • document:必选,要插入的文档(JSON格式对象),字段可自定义。
    • 示例:向users集合插入一条用户文档
      db.users.insertOne({
        username: "lisi",
        age: 30,
        status: "active"
      })
      
    • 插入成功后,MongoDB会自动为文档添加_id字段(唯一标识,若未指定则自动生成ObjectId)。
  • db.集合名字.insertMany(documents, options):向集合中插入多条文档

    • documents:必选,文档数组(包含多个JSON对象)。
    • options:可选,配置项,如ordered: true(默认,按顺序插入,失败则终止)、ordered: false(并行插入以提高插入性能,忽略单条失败)。
    • 示例:批量插入用户文档
      db.users.insertMany([
        { username: "wangwu", age: 28, status: "inactive" },
        { username: "zhaoliu", age: 35, status: "active" }
      ])
      
  • db.集合名字.find(query, projection)查询集合中的文档,返回所有符合条件的结果(默认返回全部字段)。

    • query:可选,查询条件(JSON对象),不指定则返回所有文档。
    • projection:可选,投影设置(指定返回哪些字段),1表示显示,0表示隐藏(_id默认显示,需显式设置0隐藏)。
    • 示例:
      • 查询所有状态为active的用户:
        db.users.find({ status: "active" })
        
      • 查询年龄大于25的用户,只返回usernameage字段:
        db.users.find({ age: { $gt: 25 } }, { username: 1, age: 1, _id: 0 })
        
    • 常用查询操作符:$eq(等于)、$gt(大于)、$lt(小于)、$in(在数组中)、$and(逻辑与)等。
  • db.集合名字.findOne(query, projection)查询符合条件的第一条文档(返回单个文档,而非数组)。

    • 参数同find(),适用于获取唯一结果(如按_id查询)。
    • 示例:查询usernamelisi的用户
      db.users.findOne({ username: "lisi" })
      
  • db.集合名字.updateOne(filter, update, options)更新符合条件的第一条文档

    • filter:必选,筛选条件(同查询的query)。
    • update:必选,更新操作(需使用更新操作符,如$set$inc等)。
    • options:可选,如upsert: true(若文档不存在则插入新文档)。
    • 示例:将lisi的年龄更新为31
      db.users.updateOne(
        { username: "lisi" },  // 筛选条件
        { $set: { age: 31 } }  // 更新操作:设置age字段
      )
      
    • 常用更新操作符:$set(修改字段值)、$inc(数值增减)、$push(向数组添加元素)、$unset(删除字段)等。
  • db.集合名字.updateMany(filter, update, options)更新所有符合条件的文档

    • 参数同updateOne(),但会批量更新匹配的所有文档。
    • 示例:将所有statusinactive的用户年龄增加1
      db.users.updateMany(
        { status: "inactive" },
        { $inc: { age: 1 } }  // 年龄+1
      )
      
  • db.集合名字.replaceOne(filter, replacement, options)替换符合条件的第一条文档(用新文档完全覆盖旧文档,保留_id)。

    • replacement:必选,用于替换的新文档(不含更新操作符)。
    • 示例:替换wangwu的文档内容
      db.users.replaceOne(
        { username: "wangwu" },
        { username: "wangwu", age: 29, status: "active", hobby: "reading" }
      )
      
  • db.集合名字.deleteOne(filter)删除符合条件的第一条文档

    • filter:必选,筛选条件(同查询)。
    • 示例:删除usernamezhaoliu的文档
      db.users.deleteOne({ username: "zhaoliu" })
      
  • db.集合名字.deleteMany(filter)删除所有符合条件的文档

    • 示例:删除所有statusinactive的文档
      db.users.deleteMany({ status: "inactive" })
      
  • db.集合名字.countDocuments(query)统计符合条件的文档数量

    • query:可选,筛选条件,不指定则统计集合总文档数。
    • 示例:统计状态为active的用户数量
      db.users.countDocuments({ status: "active" })
      
  • db.集合名字.distinct(field, query)查询指定字段的去重值,返回数组。

    • field:必选,要去重的字段名。
    • query:可选,筛选条件。
    • 示例:查询所有用户的status去重后的值
      db.users.distinct("status")  // 返回 ["active", "inactive"]
      
  • db.集合名字.aggregate(pipeline)聚合查询(复杂数据处理,如分组、统计、关联等)。

    • pipeline:必选,聚合管道数组(由多个聚合阶段组成)。
    • 示例:按status分组统计用户数量
      db.users.aggregate([
        { $group: { _id: "$status", count: { $sum: 1 } } }
      ])
      
    • 常用聚合阶段:$match(筛选)、$group(分组)、$sort(排序)、$limit(限制数量)等。

2.5 规范及常见问题解决

数据库命名规范

1、命名规则

// 正确的数据库名
use myapp          // 小写字母
use user_management // 下划线分隔
use test123        // 包含数字

// 错误的数据库名
use MyApp          // 避免大写字母
use user-management // 避免连字符
use 123test        // 不能以数字开头
use my app         // 不能包含空格

2、最佳实践

// 使用有意义的名称
use ecommerce_db    // 电商数据库
use blog_system     // 博客系统数据库
use school_management // 学校管理数据库

// 避免使用特殊字符
// 避免使用MongoDB保留字
// 使用小写字母和下划线

故障排除

问题1:数据库不显示

// 原因:数据库为空
use myapp
db.users.insertOne({"test": "data"})
show dbs
// 现在应该能看到myapp

问题2:无法创建数据库

// 检查权限
use admin
db.auth("admin", "password")

// 检查磁盘空间
db.stats()

问题3:集合创建失败

// 检查集合名是否合法
// 集合名不能以"system."开头
db.createCollection("mycollection") // 正确
db.createCollection("system.test")  // 错误

2.6 实际应用示例

第一步:连接到MongoDB

启动MongoDB Shell
# 连接到本地MongoDB
mongosh

# 连接到远程MongoDB
mongosh --host 192.168.1.100 --port 27017

# 连接到特定数据库
mongosh --db myapp
基本连接操作
// 查看当前数据库
db

// 查看所有数据库
show dbs

// 查看当前数据库的所有集合
show collections

第二步:创建第一个数据库

使用use命令创建数据库
// 切换到(或创建)名为"myapp"的数据库
use myapp

// 查看当前数据库
db
// 输出: myapp

// 查看所有数据库
show dbs
// 注意:此时myapp数据库可能还不会显示
为什么新创建的数据库不显示?
// 刚创建的数据库不会立即显示在列表中
use myapp
show dbs
// 输出可能不包含myapp

// 需要插入数据后才会显示
db.users.insertOne({"name": "张三", "age": 25})
show dbs
// 现在myapp会显示在列表中

第三步:向数据库插入数据

插入第一条数据
// 切换到myapp数据库
use myapp

// 插入一条用户数据
db.users.insertOne({
  "name": "张三",
  "email": "zhangsan@example.com",
  "age": 25,
  "created_at": new Date()
})

// 查看插入结果
// 输出: { "acknowledged" : true, "insertedId" : ObjectId("...") }
插入多条数据
// 插入多条用户数据
db.users.insertMany([
  {
    "name": "李四",
    "email": "lisi@example.com",
    "age": 30,
    "created_at": new Date()
  },
  {
    "name": "王五",
    "email": "wangwu@example.com",
    "age": 28,
    "created_at": new Date()
  }
])
验证数据库创建
// 查看所有数据库
show dbs
// 现在应该能看到myapp数据库

// 查看当前数据库的集合
show collections
// 应该能看到users集合

// 查看集合中的数据
db.users.find()

第四步:创建集合

方法一:自动创建集合
// 插入数据时自动创建集合
use myapp
db.products.insertOne({
  "name": "笔记本电脑",
  "price": 5999,
  "category": "电子产品"
})
方法二:显式创建集合
// 显式创建集合
use myapp
db.createCollection("orders")

// 查看所有集合
show collections
// 输出: orders, products, users
创建带选项的集合
// 创建固定大小的集合(适合存储日志)
db.createCollection("logs", {
  capped: true,
  size: 100000,  // 100KB
  max: 1000      // 最多1000个文档
})

// 创建带验证规则的集合
db.createCollection("employees", {
  validator: {
    $jsonSchema: {
      bsonType: "object",
      required: ["name", "email"],
      properties: {
        name: {
          bsonType: "string",
          description: "姓名必须是字符串"
        },
        email: {
          bsonType: "string",
          pattern: "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
          description: "邮箱格式不正确"
        }
      }
    }
  }
})

第五步:数据库操作

查看数据库信息
// 查看当前数据库
db

// 查看数据库统计信息
db.stats()

// 查看数据库名称
db.getName()
删除数据库
// 切换到要删除的数据库
use testdb

// 删除当前数据库
db.dropDatabase()

// 验证删除
show dbs
// testdb应该不再显示
复制数据库
// 复制数据库(需要管理员权限)
use admin
db.copyDatabase("source_db", "target_db", "localhost:27017")
实际应用场景:电商网站数据库
// 创建电商数据库
use ecommerce

// 创建用户集合
db.users.insertOne({
  "username": "customer1",
  "email": "customer1@example.com",
  "profile": {
    "firstName": "张",
    "lastName": "三",
    "phone": "13800138000"
  },
  "addresses": [
    {
      "type": "home",
      "street": "中关村大街1号",
      "city": "北京",
      "zipCode": "100080"
    }
  ],
  "created_at": new Date()
})

// 创建产品集合
db.products.insertOne({
  "name": "iPhone 15",
  "category": "手机",
  "brand": "Apple",
  "price": 6999,
  "stock": 100,
  "specifications": {
    "color": "黑色",
    "storage": "128GB",
    "screen": "6.1英寸"
  },
  "created_at": new Date()
})

// 创建订单集合
db.orders.insertOne({
  "orderId": "ORD001",
  "userId": "customer1",
  "items": [
    {
      "productId": "iPhone 15",
      "quantity": 1,
      "price": 6999
    }
  ],
  "total": 6999,
  "status": "pending",
  "created_at": new Date()
})

网站公告

今日签到

点亮在社区的每一天
去签到