TOC
KINA

KINA-0

Start having fun with KINA right now!

MongoDB分布式文档数据库简介

MongoDB是一个开源、跨平台、分布式文档数据库,属于NoSQL(Not Only SQL)数据库的一种。

Mac版官方文档:在macOS上安装MongoDB Community Edition

1 MongoDB概述

MongoDB是一个面向文档的数据库,使用文档(document)对象存储数据
可扩展: 可以将数据分布式存储到多个服务器中,同时可以自动管理跨节点的负载均衡,将数据操作路由到相应的服务器。

MongoDB简单易用,功能丰富,数据存储性能高。

1.1 数据格式

在MongoDB中,数据使用JSON或者BSON格式进行处理和存储。

  • JSON(JavaScript Object Notation):一种轻量级的数据交换格式,一个JSON文档就是一个由字段和值组成的集合,遵循特定的格式。
  • BSON(Binary JSON):一种类 JSON 文档的二进制序列化,BSON更注重存储和处理的效率。

由于MongoDB本身不支持SQL语句,因此在初始化数据时常直接导入JSON等格式文件,或通过insertOne()等插入语句将JSON数据进行插入。

1.2 文档(Document)

MongoDB以BSON文档的形式存储数据记录,简称为文档(Document)。

结构如下:

{
   field_name1: value1,
   field_name2: value2,
   field_name3: value3,
   ...
}

实例:

{
    _id: ObjectId("5f339953491024badf1138ec"),
    title: “数据库系统概论",
    isbn: “9787040406641",
    publisher: “高等教育出版社",
    published_date: new Date(‘2014-9-01'),
    author: { first_name: “珊", last_name: "王"}
}

1.3 集合(Collection)

MongoDB使用集合(Colletion)存储文档,一个集合就是一组文档。

新建数据库后,应使用createCollection()语句新建集合,之后即可进行数据操作。

MongoDB RDBMS
文档
集合

特点:

  1. 集合的模式为动态的,集合中的文档结构可以完全不同
  2. 一个集合拥有一个名字
  3. 集合的名字不能包含以下内容
    • $字符
    • null(\0)字符
    • 空字符串
    • system开头

1.4 数据库(DataBase)

集合(Collection)存储在数据库中,一个MongoDB实例可以包含多个数据库。

admin、local和config为系统保留数据库名称,不能使用这些名字创建新的数据库。


2 数据类型

  • 空类型
  • 布尔类型
  • 数字类型
  • 字符串类型
  • 日期类型
  • 正则表达式
  • 数组类型
  • 嵌入式文档
  • 对象ID

3 创建文档

3.1 insertOne()

3.1.1 不指定_id

db.products.insertOne({
    "name": "xiaomi",
    "price": 799,
    "releaseDate": ISODate("2019-05-14"),
    "spec": {"ram": 4, "screen": 6.5, "cpu": 2.66},
    "color": ["white", "black"],
    "storage": [64,128,256]
});
{
    acknowledged: true,
    insertedId: ObjectId("65413081059fcf9ea192cda6")
}

3.1.2 指定_id

db.products.insertOne({
    "_id": 2,
    "name": "huawei",
    "price": 899,
    "releaseDate": ISODate("2021-09-01"),
    "spec": {"ram": 16,"screen": 9.5,"cpu": 3.66},
    "color": ["white", "black", "purple"],
    "storage": [128, 256, 512]
});
{
    acknowledged: true,
    insertedId: 2
}

3.1.3 _id冲突

db.products.insertOne({
    "_id": 2, 
    "name": "sanxing", 
    "price": 1299, 
    "releaseDate": ISODate("2018-01-14"), 
    "spec": { "ram": 12, "screen": 9.7, "cpu": 3.66 },
    "color": ["blue"],
    "storage": [16, 64, 128]
});
MongoServerError: E11000 duplicate key error collection: course.products index: _id_ dup key: { _id: 2 }

3.2 insertMany()

3.2.1 顺序插入

db.products.insertMany([
    {
        "_id": 1,
        "name": "xiaomi", 
        "price": 799, 
        "releaseDate": ISODate("2021-05-14"), 
        "spec": { "ram" : 4, "screen" : 6.5, "cpu" : 2.66 },
        "color": ["white", "black"],
        "storage":[64, 128, 256]
    },
    {
        "_id": 2, 
        "name": "huawei", 
        "price": 899, 
        "releaseDate": ISODate("2022-09-01") , 
        "spec": { "ram" : 16, "screen" : 9.5, "cpu" : 3.66 },
        "color": ["white", "black", "purple"],
        "storage":[128, 256, 512]
    },
    {
        "_id": 3, 
        "name": "sanxing", 
        "price": 899, 
        "releaseDate": ISODate("2023-01-14"), 
        "spec": { "ram" : 12, "screen" : 9.7, "cpu" : 3.66 },
        "color": ["blue"],
        "storage":[16, 64, 128]
    }
])
MongoServerError: E11000 duplicate key error collection: course.products index: _id_ dup key: { _id: 1 }.

使用顺序插入,在_id有冲突的情况下,所有文档均未插入

3.2.2 无序插入

db.products.insertOne({
    "_id": 2, 
    "name": "sanxing", 
    "price": 1299, 
    "releaseDate": ISODate("2018-01-14"), 
    "spec": { "ram": 12, "screen": 9.7, "cpu": 3.66 },
    "color": ["blue"],
    "storage": [16, 64, 128]
});
MongoServerError: E11000 duplicate key error collection: course.products index: _id_ dup key: { _id: 2 }

无序插入的情况与有序插入不同,此时_id为3的文档已经插入。


4 查找文档

4.1 findOne()

【例1】查找products集合中的第一个文档

db.products.findOne();
{
  _id: ObjectId("65413081059fcf9ea192cda6"),
  name: 'xiaomi',
  price: 799,
  releaseDate: 2019-05-14T00:00:00.000Z,
  spec: {
    ram: 4,
    screen: 6.5,
    cpu: 2.66
  },
  color: [
    'white',
    'black'
  ],
  storage: [
    64,
    128,
    256
  ]
}

【例2】查找_id为3的文档

db.products.findOne({_id: 3})
{
  _id: 3,
  name: 'sanxing',
  price: 899,
  releaseDate: 2023-01-14T00:00:00.000Z,
  spec: {
    ram: 12,
    screen: 9.7,
    cpu: 3.66
  },
  color: [
    'blue'
  ],
  storage: [
    16,
    64,
    128
  ]
}

【例3】查找_id等于2的文档,只返回_idname

db.products.findOne({_id: 2}, {name: 1})
{
  _id: 2,
  name: 'huawei'
}

4.2 find()

【例1】查找products的所有文档

db.products.find();

返回products中所有文档(默认20个文档一页,通过it来翻页)

【例2】查找name为huawei的文档

db.products.find({name: 'huawei'})
{
  _id: 2,
  name: 'huawei',
  price: 899,
  releaseDate: 2021-09-01T00:00:00.000Z,
  spec: {
    ram: 16,
    screen: 9.5,
    cpu: 3.66
  },
  color: [
    'white',
    'black',
    'purple'
  ],
  storage: [
    128,
    256,
    512
  ]
}

【例3】查找name为xiaomi的文档,返回_idpricespec中的ram

db.products.find({name: 'xiaomi'}, {_id: 1, price: 1, 'spec.ram': 1})
{
  _id: ObjectId("65413081059fcf9ea192cda6"),
  price: 799,
  spec: {
    ram: 4
  }
}

4.3 比较运算符

比较运算符 等价于MySQL关系运算符
$eq ==
$gt >
$gte >=
$lt <
$lte <=
$ne !=
$in in
$nin not in

【例1】$gt示例

db.products.find({'spec.ram': {$gt: 4}},{_id: 1, name: 1, 'spec.ram': 1})
{
    _id: 2,
    name: 'huawei',
    spec: {
        ram: 16
    }
}
{
    _id: 1,
    name: 'sanxing',
    spec: {
        ram: 12
    }
}
{
    _id: 3,
    name: 'sanxing',
    spec: {
        ram: 12
    }
}
{
    _id: 4,
    name: 'SmartPad',
    spec: {
        ram: 8
    }
}

【例2】$in示例:查找ram是4或8的文档信息

db.products.find({'spec.ram': {$in: [4,8]}}, {_id: 1, name: 1, 'spec.ram': 1})
{
    _id: ObjectId("65413081059fcf9ea192cda6"),
    name: 'xiaomi',
    spec: {
        ram: 4
    }
}
{
    _id: 4,
    name: 'SmartPad',
    spec: {
        ram: 8
    }
}
{
    _id: 5,
    name: 'SmartPhone',
    spec: {
        ram: 4
    }
}

其他语法详见官方文档


5 练习

实践出真知

5.1 例1

使用元素运算符中的$exists$type构建查询语句,并给出结果

db.course.find({ Cpno: { $exists: true } });
{ "Cno" : "1", "CName" : "数据库", "Cpno" : "5", "Ccredit" : 4 }
{ "Cno" : "3", "CName" : "信息系统", "Cpno" : "1", "Ccredit" : 4 }
{ "Cno" : "4", "CName" : "操作系统", "Cpno" : "6", "Ccredit" : 3 }
{ "Cno" : "5", "CName" : "数据结构", "Cpno" : "7", "Ccredit" : 4 }
{ "Cno" : "7", "CName" : "PASCAL语言", "Cpno" : "6", "Ccredit" : 4 }
db.student.find({ Sname: { $type: "string" } });
{ "sno" : "201215121", "sname" : "李勇", "Ssex" : "男", "Sage" : 20, "Sdept" : "CS" }
{ "sno" : "201215122", "sname" : "刘晨", "Ssex" : "男", "Sage" : 19, "Sdept" : "CS" }
{ "sno" : "201215125", "sname" : "张丽", "Ssex" : "男", "Sage" : 19, "Sdept" : "IS" }
{ "sno" : "201215130", "sname" : "刘%", "Ssex" : "女", "Sage" : 21, "Sdept" : "MA" }

5.2 例2

使用数组运算符中的$size$all$elemMatch构建查询语句,并给出结果

db.sc.aggregate([
    { $group: { _id: "$sno", count: { $sum: 1 } } },
    { $match: { count: 2 } }
]);
{ "_id" : "201215122", "count" : 2 }
db.sc.find({ $all: [{ Grade: "1" }, { Grade: "2" }] });
{ "sno" : "201215121", "cno" : "1", "Grade" : "92" }
{ "sno" : "201215121", "cno" : "2", "Grade" : "85" }
db.sc.find({
    $elemMatch: { Grade: { $gt: 70 } }
});
{ "sno" : "201215121", "cno" : "1", "Grade" : "92" }

5.3 例3

使用sort()skip()limit()构建查询语句,并给出结果

db.course.find().sort({ Ccredit: -1 }).skip(2).limit(2);
{ "Cno" : "4", "CName" : "操作系统", "Cpno" : "6", "Ccredit" : 3 }
{ "Cno" : "2", "CName" : "数学", "Cpno" : null, "Ccredit" : 2 }

5.4 例4

使用updateOne()updateMany(),结合$inc$min$max$mul$unset$rename,构建更新语句,并给出结果

db.course.updateOne(
    { Ccredit: 4 },
    { $set: { Ccredit: 5 } }
);
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
db.course.updateMany(
    {},
    { $inc: { Ccredit: 1 } }
);
{ "acknowledged" : true, "matchedCount" : 7, "modifiedCount" : 7 }
db.student.updateOne(
    { sno: '201215121' },
    { $min: { Sage: 21 } }
);
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 0 }
db.student.updateMany(
    {},
    { $mul: { Sage: 2 } }
);
{ "acknowledged" : true, "matchedCount" : 4, "modifiedCount" : 4 }
db.student.updateOne(
    { sno: '201215122' },
    { $unset: { Ssex: "" } }
);
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }
db.student.updateOne(
    { sno: '201215125' },
    { $rename: { Sdept: "Department" } }
);
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }

5.5 例5

使用deleteOne()deleteMany()构建删除语句,并给出结果

db.course.deleteOne({ CName: "数据库" });
{ "acknowledged" : true, "deletedCount" : 1 }
db.course.deleteMany({ Ccredit: { $lt: 3 } });
{ "acknowledged" : true, "deletedCount" : 2 }

5.6 例6

给出聚合操作aggregate()的使用方法,说明其与find()的差别,并给出实例

db.sc.aggregate([
    { $group: { _id: "$cno", avgGrade: { $avg: "$Grade" } } }
]);
{ "_id" : "1", "avgGrade" : 82 }
{ "_id" : "2", "avgGrade" : 80 }

5.7 例7

简述如何在mongoDB中实现多表关联查询,并给出实例

db.sc.aggregate([
    {
        $lookup: {
            from: "course",
            localField: "cno",
            foreignField: "Cno",
            as: "courseInfo"
        }
    }
]);
{
    "sno" : "201215121", 
    "cno" : "1", 
    "Grade" : "92", 
    "courseInfo" : [ { "Cno" : "1", "CName" : "数据库", "Cpno" : "5", "Ccredit" : 4 } ] 
}

发表评论